electron/patches/mips64el/chromium/backport-sqlite-8a87f7e.patch
Jeremy Apthorp 76c5f5cc8a
build: move libcc patches to electron repo (#14104)
In the GN build, libchromiumcontent is no longer a distinct library, but
merely a container for a set of scripts and patches. Maintaining those
patches in a separate repository is tedious and error-prone, so merge
them into the main repo.

Once this is merged and GN is the default way to build Electron, the
libchromiumcontent repository can be archived.
2018-09-13 22:02:16 -07:00

53617 lines
1.9 MiB

commit e0f29fbf1b81b5aa9ecc4b55c09dec21a73394ec
Author: Victor Costan <pwnall@chromium.org>
Date: Fri Nov 10 01:29:30 2017 +0000
sqlite: Upgrade from 3.20.1 to 3.21.0.
Release notes for the new version:
https://sqlite.org/releaselog/3_21_0.html
Patch 0003 (Modify default VFS to support WebDatabase) was updated to
reflect conflicts introduced by the following commits:
* https://www.sqlite.org/src/info/3075cfa07489eaf1
* https://www.sqlite.org/src/info/1a7e0b61c8a6bdd3
The patch was updated to reflect the rename of pUnused to
pPreallocatedUnused and an extra assert added. Both changes were in
src/os_unix.c.
Patch 0004 (Virtual table supporting recovery of corrupted databases)
was updated to reflect the addition of new compile-time flags to
main.mk.
Patch 0005 (Custom shell.c helpers to load Chromium's ICU data) was
updated to reflect conflicts introduced by
https://www.sqlite.org/src/info/36acc0a97fdcc6f5 which replaced
src/shell.c with src/shell.c.in, which is used to generate src/shell.c
via Tcl. The change in the build process also introduced conflicts in
main.mk.
Patch 0009 (Fix _CRT_RAND_S conflict in sqliteInt.h) was removed
completely. It is no longer necessary, because
https://www.sqlite.org/src/info/3a2793aa65727cbb removed the use of
_CRT_RAND_S in src/sqliteInt.h.
Patches 0012 and 0013 were removed, because they were backports for
upstream changes that fixed clusterfuzz issues. Upgrading removed the
need for backports altogether.
The new SQLite release allows ATTACH and DETACH to be used inside
transactions, so sql/connection_unittest.cc was updated to reflect the
new behavior. The test for attaching databases was broken into two
tests, covering the behavior with and without a transaction. The former
test (covering the behavior with a transaction) has separate
implementations for iOS, where we use the system SQLite, which might be
old, and every other platform, where we ship our own SQLite version.
Bug: 780626, 701522
Change-Id: I7a8378cb317966388ebe9903d9e61162d3b3d3c9
Reviewed-on: https://chromium-review.googlesource.com/754522
Reviewed-by: Chris Mumford <cmumford@chromium.org>
Commit-Queue: Victor Costan <pwnall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#515403}
diff --git a/sql/connection.h b/sql/connection.h
index 8b96407..e1e020d 100644
--- a/sql/connection.h
+++ b/sql/connection.h
@@ -392,8 +392,14 @@ class SQL_EXPORT Connection {
// handle under |attachment_point|. |attachment_point| should only
// contain characters from [a-zA-Z0-9_].
//
- // Note that calling attach or detach with an open transaction is an
- // error.
+ // Attaching a database while a transaction is open will have
+ // platform-dependent results, as explained below.
+ //
+ // On the SQLite version shipped with Chrome (3.21+, Oct 2017), databases can
+ // be attached while a transaction is opened. However, these databases cannot
+ // be detached until the transaction is committed or aborted. On iOS, the
+ // built-in SQLite might not be older than 3.21. In that case, attaching a
+ // database while a transaction is open results in a error.
bool AttachDatabase(const base::FilePath& other_db_path,
const char* attachment_point);
bool DetachDatabase(const char* attachment_point);
diff --git a/sql/connection_unittest.cc b/sql/connection_unittest.cc
index 4ee8b02..7bd01b4 100644
--- a/sql/connection_unittest.cc
+++ b/sql/connection_unittest.cc
@@ -27,7 +27,7 @@
#if defined(OS_IOS) && defined(USE_SYSTEM_SQLITE)
#include "base/ios/ios_util.h"
-#endif
+#endif // defined(OS_IOS) && defined(USE_SYSTEM_SQLITE)
namespace sql {
namespace test {
@@ -228,7 +228,7 @@ class ScopedUmaskSetter {
mode_t old_umask_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter);
};
-#endif
+#endif // defined(OS_POSIX)
// SQLite function to adjust mock time by |argv[0]| milliseconds.
void sqlite_adjust_millis(sql::test::ScopedMockTimeSource* time_mock,
@@ -847,7 +847,7 @@ TEST_F(SQLConnectionTest, RazeAndCloseDiagnostics) {
db().IsSQLValid(kSimpleSql);
}, "Illegal use of connection without a db");
}
-#endif
+#endif // !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA)
}
// TODO(shess): Spin up a background thread to hold other_db, to more
@@ -901,7 +901,7 @@ TEST_F(SQLConnectionTest, SetTempDirForSQL) {
// database file'.
ASSERT_TRUE(meta_table.Init(&db(), 4, 4));
}
-#endif
+#endif // defined(OS_ANDROID)
TEST_F(SQLConnectionTest, Delete) {
EXPECT_TRUE(db().Execute("CREATE TABLE x (x)"));
@@ -1035,8 +1035,7 @@ TEST_F(SQLConnectionTest, Poison) {
EXPECT_FALSE(db().CommitTransaction());
}
-// Test attaching and detaching databases from the connection.
-TEST_F(SQLConnectionTest, Attach) {
+TEST_F(SQLConnectionTest, AttachDatabase) {
EXPECT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
// Create a database to attach to.
@@ -1053,21 +1052,69 @@ TEST_F(SQLConnectionTest, Attach) {
// Cannot see the attached database, yet.
EXPECT_FALSE(db().IsSQLValid("SELECT count(*) from other.bar"));
+ EXPECT_TRUE(db().AttachDatabase(attach_path, kAttachmentPoint));
+ EXPECT_TRUE(db().IsSQLValid("SELECT count(*) from other.bar"));
+
+ // Queries can touch both databases after the ATTACH.
+ EXPECT_TRUE(db().Execute("INSERT INTO foo SELECT a, b FROM other.bar"));
+ {
+ sql::Statement s(db().GetUniqueStatement("SELECT COUNT(*) FROM foo"));
+ ASSERT_TRUE(s.Step());
+ EXPECT_EQ(1, s.ColumnInt(0));
+ }
+
+ EXPECT_TRUE(db().DetachDatabase(kAttachmentPoint));
+ EXPECT_FALSE(db().IsSQLValid("SELECT count(*) from other.bar"));
+}
+
+TEST_F(SQLConnectionTest, AttachDatabaseWithOpenTransaction) {
+ EXPECT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
+
+ // Create a database to attach to.
+ base::FilePath attach_path =
+ db_path().DirName().AppendASCII("SQLConnectionAttach.db");
+ const char kAttachmentPoint[] = "other";
+ {
+ sql::Connection other_db;
+ ASSERT_TRUE(other_db.Open(attach_path));
+ EXPECT_TRUE(other_db.Execute("CREATE TABLE bar (a, b)"));
+ EXPECT_TRUE(other_db.Execute("INSERT INTO bar VALUES ('hello', 'world')"));
+ }
+
+ // Cannot see the attached database, yet.
+ EXPECT_FALSE(db().IsSQLValid("SELECT count(*) from other.bar"));
+
+#if defined(OS_IOS) && defined(USE_SYSTEM_SQLITE)
+ // SQLite before 3.21 does not support ATTACH and DETACH in transactions.
+
// Attach fails in a transaction.
EXPECT_TRUE(db().BeginTransaction());
{
sql::test::ScopedErrorExpecter expecter;
expecter.ExpectError(SQLITE_ERROR);
EXPECT_FALSE(db().AttachDatabase(attach_path, kAttachmentPoint));
+ EXPECT_FALSE(db().IsSQLValid("SELECT count(*) from other.bar"));
+ ASSERT_TRUE(expecter.SawExpectedErrors());
+ }
+
+ // Detach also fails in a transaction.
+ {
+ sql::test::ScopedErrorExpecter expecter;
+ expecter.ExpectError(SQLITE_ERROR);
+ EXPECT_FALSE(db().DetachDatabase(kAttachmentPoint));
ASSERT_TRUE(expecter.SawExpectedErrors());
}
- // Attach succeeds when the transaction is closed.
db().RollbackTransaction();
+#else // defined(OS_IOS) && defined(USE_SYSTEM_SQLITE)
+ // Chrome's SQLite (3.21+) supports ATTACH and DETACH in transactions.
+
+ // Attach succeeds in a transaction.
+ EXPECT_TRUE(db().BeginTransaction());
EXPECT_TRUE(db().AttachDatabase(attach_path, kAttachmentPoint));
EXPECT_TRUE(db().IsSQLValid("SELECT count(*) from other.bar"));
- // Queries can touch both databases.
+ // Queries can touch both databases after the ATTACH.
EXPECT_TRUE(db().Execute("INSERT INTO foo SELECT a, b FROM other.bar"));
{
sql::Statement s(db().GetUniqueStatement("SELECT COUNT(*) FROM foo"));
@@ -1075,8 +1122,7 @@ TEST_F(SQLConnectionTest, Attach) {
EXPECT_EQ(1, s.ColumnInt(0));
}
- // Detach also fails in a transaction.
- EXPECT_TRUE(db().BeginTransaction());
+ // Detaching the same database fails, database is locked in the transaction.
{
sql::test::ScopedErrorExpecter expecter;
expecter.ExpectError(SQLITE_ERROR);
@@ -1085,11 +1131,11 @@ TEST_F(SQLConnectionTest, Attach) {
ASSERT_TRUE(expecter.SawExpectedErrors());
}
- // Detach succeeds outside of a transaction.
+ // Detach succeeds when the transaction is closed.
db().RollbackTransaction();
EXPECT_TRUE(db().DetachDatabase(kAttachmentPoint));
-
EXPECT_FALSE(db().IsSQLValid("SELECT count(*) from other.bar"));
+#endif // defined(OS_IOS) && defined(USE_SYSTEM_SQLITE)
}
TEST_F(SQLConnectionTest, Basic_QuickIntegrityCheck) {
@@ -1564,7 +1610,7 @@ TEST_F(SQLConnectionTest, GetAppropriateMmapSize) {
ASSERT_EQ(0UL, db().GetAppropriateMmapSize());
return;
}
-#endif
+#endif // defined(OS_IOS) && defined(USE_SYSTEM_SQLITE)
const size_t kMmapAlot = 25 * 1024 * 1024;
int64_t mmap_status = MetaTable::kMmapFailure;
@@ -1616,7 +1662,7 @@ TEST_F(SQLConnectionTest, GetAppropriateMmapSizeAltStatus) {
ASSERT_EQ(0UL, db().GetAppropriateMmapSize());
return;
}
-#endif
+#endif // defined(OS_IOS) && defined(USE_SYSTEM_SQLITE)
const size_t kMmapAlot = 25 * 1024 * 1024;
@@ -1665,7 +1711,7 @@ TEST_F(SQLConnectionTest, CompileError) {
db().GetUniqueStatement("SELECT x");
}, "SQL compile error no such column: x");
}
-#endif
+#endif // !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA)
}
} // namespace sql
diff --git a/third_party/sqlite/BUILD.gn b/third_party/sqlite/BUILD.gn
index a518797..795bd8b 100644
--- a/third_party/sqlite/BUILD.gn
+++ b/third_party/sqlite/BUILD.gn
@@ -204,7 +204,7 @@ if (!use_system_sqlite) {
include_dirs = [ "amalgamation" ]
sources = [
- "src/src/shell.c",
+ "amalgamation/shell.c",
"src/src/shell_icu_linux.c",
# Include a dummy c++ file to force linking of libstdc++.
diff --git a/third_party/sqlite/README.chromium b/third_party/sqlite/README.chromium
index 247200b..8a0fd02 100644
--- a/third_party/sqlite/README.chromium
+++ b/third_party/sqlite/README.chromium
@@ -1,6 +1,6 @@
Name: sqlite
URL: https://sqlite.org/
-Version: 3.20.patched
+Version: 3.21.0
Included In Release: Yes
Security Critical: Yes
License: Public domain
diff --git a/third_party/sqlite/amalgamation/shell.c b/third_party/sqlite/amalgamation/shell.c
new file mode 100644
index 0000000..1b3e555
--- /dev/null
+++ b/third_party/sqlite/amalgamation/shell.c
@@ -0,0 +1,8393 @@
+/* DO NOT EDIT!
+** This file is automatically generated by the script in the canonical
+** SQLite source tree at tool/mkshellc.tcl. That script combines source
+** code from various constituent source files of SQLite into this single
+** "shell.c" file used to implement the SQLite command-line shell.
+**
+** Most of the code found below comes from the "src/shell.c.in" file in
+** the canonical SQLite source tree. That main file contains "INCLUDE"
+** lines that specify other files in the canonical source tree that are
+** inserted to getnerate this complete program source file.
+**
+** The code from multiple files is combined into this single "shell.c"
+** source file to help make the command-line program easier to compile.
+**
+** To modify this program, get a copy of the canonical SQLite source tree,
+** edit the src/shell.c.in" and/or some of the other files that are included
+** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script.
+*/
+/*
+** 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 file contains code to implement the "sqlite" command line
+** utility for accessing SQLite databases.
+*/
+#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
+/* This needs to come before any includes for MSVC compiler */
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+/*
+** Warning pragmas copied from msvc.h in the core.
+*/
+#if defined(_MSC_VER)
+#pragma warning(disable : 4054)
+#pragma warning(disable : 4055)
+#pragma warning(disable : 4100)
+#pragma warning(disable : 4127)
+#pragma warning(disable : 4130)
+#pragma warning(disable : 4152)
+#pragma warning(disable : 4189)
+#pragma warning(disable : 4206)
+#pragma warning(disable : 4210)
+#pragma warning(disable : 4232)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4305)
+#pragma warning(disable : 4306)
+#pragma warning(disable : 4702)
+#pragma warning(disable : 4706)
+#endif /* defined(_MSC_VER) */
+
+/*
+** No support for loadable extensions in VxWorks.
+*/
+#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION
+# define SQLITE_OMIT_LOAD_EXTENSION 1
+#endif
+
+/*
+** Enable large-file support for fopen() and friends on unix.
+*/
+#ifndef SQLITE_DISABLE_LFS
+# define _LARGE_FILE 1
+# ifndef _FILE_OFFSET_BITS
+# define _FILE_OFFSET_BITS 64
+# endif
+# define _LARGEFILE_SOURCE 1
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include "sqlite3.h"
+#if SQLITE_USER_AUTHENTICATION
+# include "sqlite3userauth.h"
+#endif
+#include <ctype.h>
+#include <stdarg.h>
+
+#if !defined(_WIN32) && !defined(WIN32)
+# include <signal.h>
+# if !defined(__RTP__) && !defined(_WRS_KERNEL)
+# include <pwd.h>
+# endif
+# include <unistd.h>
+# include <sys/types.h>
+#endif
+
+#if HAVE_READLINE
+# include <readline/readline.h>
+# include <readline/history.h>
+#endif
+
+#if HAVE_EDITLINE
+# include <editline/readline.h>
+#endif
+
+#if HAVE_EDITLINE || HAVE_READLINE
+
+# define shell_add_history(X) add_history(X)
+# define shell_read_history(X) read_history(X)
+# define shell_write_history(X) write_history(X)
+# define shell_stifle_history(X) stifle_history(X)
+# define shell_readline(X) readline(X)
+
+#elif HAVE_LINENOISE
+
+# include "linenoise.h"
+# define shell_add_history(X) linenoiseHistoryAdd(X)
+# define shell_read_history(X) linenoiseHistoryLoad(X)
+# define shell_write_history(X) linenoiseHistorySave(X)
+# define shell_stifle_history(X) linenoiseHistorySetMaxLen(X)
+# define shell_readline(X) linenoise(X)
+
+#else
+
+# define shell_read_history(X)
+# define shell_write_history(X)
+# define shell_stifle_history(X)
+
+# define SHELL_USE_LOCAL_GETLINE 1
+#endif
+
+
+#if defined(_WIN32) || defined(WIN32)
+# include <io.h>
+# include <fcntl.h>
+# define isatty(h) _isatty(h)
+# ifndef access
+# define access(f,m) _access((f),(m))
+# endif
+# undef popen
+# define popen _popen
+# undef pclose
+# define pclose _pclose
+#else
+ /* Make sure isatty() has a prototype. */
+ extern int isatty(int);
+
+# if !defined(__RTP__) && !defined(_WRS_KERNEL)
+ /* popen and pclose are not C89 functions and so are
+ ** sometimes omitted from the <stdio.h> header */
+ extern FILE *popen(const char*,const char*);
+ extern int pclose(FILE*);
+# else
+# define SQLITE_OMIT_POPEN 1
+# endif
+#endif
+
+#if defined(_WIN32_WCE)
+/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
+ * thus we always assume that we have a console. That can be
+ * overridden with the -batch command line option.
+ */
+#define isatty(x) 1
+#endif
+
+/* ctype macros that work with signed characters */
+#define IsSpace(X) isspace((unsigned char)X)
+#define IsDigit(X) isdigit((unsigned char)X)
+#define ToLower(X) (char)tolower((unsigned char)X)
+
+#if defined(_WIN32) || defined(WIN32)
+#include <windows.h>
+
+/* string conversion routines only needed on Win32 */
+extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
+extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int);
+extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
+extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
+#endif
+
+/* On Windows, we normally run with output mode of TEXT so that \n characters
+** are automatically translated into \r\n. However, this behavior needs
+** to be disabled in some cases (ex: when generating CSV output and when
+** rendering quoted strings that contain \n characters). The following
+** routines take care of that.
+*/
+#if defined(_WIN32) || defined(WIN32)
+static void setBinaryMode(FILE *file, int isOutput){
+ if( isOutput ) fflush(file);
+ _setmode(_fileno(file), _O_BINARY);
+}
+static void setTextMode(FILE *file, int isOutput){
+ if( isOutput ) fflush(file);
+ _setmode(_fileno(file), _O_TEXT);
+}
+#else
+# define setBinaryMode(X,Y)
+# define setTextMode(X,Y)
+#endif
+
+
+/* True if the timer is enabled */
+static int enableTimer = 0;
+
+/* Return the current wall-clock time */
+static sqlite3_int64 timeOfDay(void){
+ static sqlite3_vfs *clockVfs = 0;
+ sqlite3_int64 t;
+ if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
+ if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
+ clockVfs->xCurrentTimeInt64(clockVfs, &t);
+ }else{
+ double r;
+ clockVfs->xCurrentTime(clockVfs, &r);
+ t = (sqlite3_int64)(r*86400000.0);
+ }
+ return t;
+}
+
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
+#include <sys/time.h>
+#include <sys/resource.h>
+
+/* VxWorks does not support getrusage() as far as we can determine */
+#if defined(_WRS_KERNEL) || defined(__RTP__)
+struct rusage {
+ struct timeval ru_utime; /* user CPU time used */
+ struct timeval ru_stime; /* system CPU time used */
+};
+#define getrusage(A,B) memset(B,0,sizeof(*B))
+#endif
+
+/* Saved resource information for the beginning of an operation */
+static struct rusage sBegin; /* CPU time at start */
+static sqlite3_int64 iBegin; /* Wall-clock time at start */
+
+/*
+** Begin timing an operation
+*/
+static void beginTimer(void){
+ if( enableTimer ){
+ getrusage(RUSAGE_SELF, &sBegin);
+ iBegin = timeOfDay();
+ }
+}
+
+/* Return the difference of two time_structs in seconds */
+static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
+ return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
+ (double)(pEnd->tv_sec - pStart->tv_sec);
+}
+
+/*
+** Print the timing results.
+*/
+static void endTimer(void){
+ if( enableTimer ){
+ sqlite3_int64 iEnd = timeOfDay();
+ struct rusage sEnd;
+ getrusage(RUSAGE_SELF, &sEnd);
+ printf("Run Time: real %.3f user %f sys %f\n",
+ (iEnd - iBegin)*0.001,
+ timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
+ timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
+ }
+}
+
+#define BEGIN_TIMER beginTimer()
+#define END_TIMER endTimer()
+#define HAS_TIMER 1
+
+#elif (defined(_WIN32) || defined(WIN32))
+
+/* Saved resource information for the beginning of an operation */
+static HANDLE hProcess;
+static FILETIME ftKernelBegin;
+static FILETIME ftUserBegin;
+static sqlite3_int64 ftWallBegin;
+typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME,
+ LPFILETIME, LPFILETIME);
+static GETPROCTIMES getProcessTimesAddr = NULL;
+
+/*
+** Check to see if we have timer support. Return 1 if necessary
+** support found (or found previously).
+*/
+static int hasTimer(void){
+ if( getProcessTimesAddr ){
+ return 1;
+ } else {
+ /* GetProcessTimes() isn't supported in WIN95 and some other Windows
+ ** versions. See if the version we are running on has it, and if it
+ ** does, save off a pointer to it and the current process handle.
+ */
+ hProcess = GetCurrentProcess();
+ if( hProcess ){
+ HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
+ if( NULL != hinstLib ){
+ getProcessTimesAddr =
+ (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
+ if( NULL != getProcessTimesAddr ){
+ return 1;
+ }
+ FreeLibrary(hinstLib);
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+** Begin timing an operation
+*/
+static void beginTimer(void){
+ if( enableTimer && getProcessTimesAddr ){
+ FILETIME ftCreation, ftExit;
+ getProcessTimesAddr(hProcess,&ftCreation,&ftExit,
+ &ftKernelBegin,&ftUserBegin);
+ ftWallBegin = timeOfDay();
+ }
+}
+
+/* Return the difference of two FILETIME structs in seconds */
+static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
+ sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
+ sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
+ return (double) ((i64End - i64Start) / 10000000.0);
+}
+
+/*
+** Print the timing results.
+*/
+static void endTimer(void){
+ if( enableTimer && getProcessTimesAddr){
+ FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
+ sqlite3_int64 ftWallEnd = timeOfDay();
+ getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
+ printf("Run Time: real %.3f user %f sys %f\n",
+ (ftWallEnd - ftWallBegin)*0.001,
+ timeDiff(&ftUserBegin, &ftUserEnd),
+ timeDiff(&ftKernelBegin, &ftKernelEnd));
+ }
+}
+
+#define BEGIN_TIMER beginTimer()
+#define END_TIMER endTimer()
+#define HAS_TIMER hasTimer()
+
+#else
+#define BEGIN_TIMER
+#define END_TIMER
+#define HAS_TIMER 0
+#endif
+
+/*
+** Used to prevent warnings about unused parameters
+*/
+#define UNUSED_PARAMETER(x) (void)(x)
+
+/*
+** If the following flag is set, then command execution stops
+** at an error if we are not interactive.
+*/
+static int bail_on_error = 0;
+
+/*
+** Threat stdin as an interactive input if the following variable
+** is true. Otherwise, assume stdin is connected to a file or pipe.
+*/
+static int stdin_is_interactive = 1;
+
+/*
+** On Windows systems we have to know if standard output is a console
+** in order to translate UTF-8 into MBCS. The following variable is
+** true if translation is required.
+*/
+static int stdout_is_console = 1;
+
+/*
+** The following is the open SQLite database. We make a pointer
+** to this database a static variable so that it can be accessed
+** by the SIGINT handler to interrupt database processing.
+*/
+static sqlite3 *globalDb = 0;
+
+/*
+** True if an interrupt (Control-C) has been received.
+*/
+static volatile int seenInterrupt = 0;
+
+/*
+** This is the name of our program. It is set in main(), used
+** in a number of other places, mostly for error messages.
+*/
+static char *Argv0;
+
+/*
+** Prompt strings. Initialized in main. Settable with
+** .prompt main continue
+*/
+static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
+static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
+
+/*
+** Render output like fprintf(). Except, if the output is going to the
+** console and if this is running on a Windows machine, translate the
+** output from UTF-8 into MBCS.
+*/
+#if defined(_WIN32) || defined(WIN32)
+void utf8_printf(FILE *out, const char *zFormat, ...){
+ va_list ap;
+ va_start(ap, zFormat);
+ if( stdout_is_console && (out==stdout || out==stderr) ){
+ char *z1 = sqlite3_vmprintf(zFormat, ap);
+ char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
+ sqlite3_free(z1);
+ fputs(z2, out);
+ sqlite3_free(z2);
+ }else{
+ vfprintf(out, zFormat, ap);
+ }
+ va_end(ap);
+}
+#elif !defined(utf8_printf)
+# define utf8_printf fprintf
+#endif
+
+/*
+** Render output like fprintf(). This should not be used on anything that
+** includes string formatting (e.g. "%s").
+*/
+#if !defined(raw_printf)
+# define raw_printf fprintf
+#endif
+
+/*
+** Write I/O traces to the following stream.
+*/
+#ifdef SQLITE_ENABLE_IOTRACE
+static FILE *iotrace = 0;
+#endif
+
+/*
+** This routine works like printf in that its first argument is a
+** format string and subsequent arguments are values to be substituted
+** in place of % fields. The result of formatting this string
+** is written to iotrace.
+*/
+#ifdef SQLITE_ENABLE_IOTRACE
+static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
+ va_list ap;
+ char *z;
+ if( iotrace==0 ) return;
+ va_start(ap, zFormat);
+ z = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ utf8_printf(iotrace, "%s", z);
+ sqlite3_free(z);
+}
+#endif
+
+/*
+** Output string zUtf to stream pOut as w characters. If w is negative,
+** then right-justify the text. W is the width in UTF-8 characters, not
+** in bytes. This is different from the %*.*s specification in printf
+** since with %*.*s the width is measured in bytes, not characters.
+*/
+static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
+ int i;
+ int n;
+ int aw = w<0 ? -w : w;
+ char zBuf[1000];
+ if( aw>(int)sizeof(zBuf)/3 ) aw = (int)sizeof(zBuf)/3;
+ for(i=n=0; zUtf[i]; i++){
+ if( (zUtf[i]&0xc0)!=0x80 ){
+ n++;
+ if( n==aw ){
+ do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
+ break;
+ }
+ }
+ }
+ if( n>=aw ){
+ utf8_printf(pOut, "%.*s", i, zUtf);
+ }else if( w<0 ){
+ utf8_printf(pOut, "%*s%s", aw-n, "", zUtf);
+ }else{
+ utf8_printf(pOut, "%s%*s", zUtf, aw-n, "");
+ }
+}
+
+
+/*
+** Determines if a string is a number of not.
+*/
+static int isNumber(const char *z, int *realnum){
+ if( *z=='-' || *z=='+' ) z++;
+ if( !IsDigit(*z) ){
+ return 0;
+ }
+ z++;
+ if( realnum ) *realnum = 0;
+ while( IsDigit(*z) ){ z++; }
+ if( *z=='.' ){
+ z++;
+ if( !IsDigit(*z) ) return 0;
+ while( IsDigit(*z) ){ z++; }
+ if( realnum ) *realnum = 1;
+ }
+ if( *z=='e' || *z=='E' ){
+ z++;
+ if( *z=='+' || *z=='-' ) z++;
+ if( !IsDigit(*z) ) return 0;
+ while( IsDigit(*z) ){ z++; }
+ if( realnum ) *realnum = 1;
+ }
+ return *z==0;
+}
+
+/*
+** Compute a string length that is limited to what can be stored in
+** lower 30 bits of a 32-bit signed integer.
+*/
+static int strlen30(const char *z){
+ const char *z2 = z;
+ while( *z2 ){ z2++; }
+ return 0x3fffffff & (int)(z2 - z);
+}
+
+/*
+** Return the length of a string in characters. Multibyte UTF8 characters
+** count as a single character.
+*/
+static int strlenChar(const char *z){
+ int n = 0;
+ while( *z ){
+ if( (0xc0&*(z++))!=0x80 ) n++;
+ }
+ return n;
+}
+
+/*
+** This routine reads a line of text from FILE in, stores
+** the text in memory obtained from malloc() and returns a pointer
+** to the text. NULL is returned at end of file, or if malloc()
+** fails.
+**
+** If zLine is not NULL then it is a malloced buffer returned from
+** a previous call to this routine that may be reused.
+*/
+static char *local_getline(char *zLine, FILE *in){
+ int nLine = zLine==0 ? 0 : 100;
+ int n = 0;
+
+ while( 1 ){
+ if( n+100>nLine ){
+ nLine = nLine*2 + 100;
+ zLine = realloc(zLine, nLine);
+ if( zLine==0 ) return 0;
+ }
+ if( fgets(&zLine[n], nLine - n, in)==0 ){
+ if( n==0 ){
+ free(zLine);
+ return 0;
+ }
+ zLine[n] = 0;
+ break;
+ }
+ while( zLine[n] ) n++;
+ if( n>0 && zLine[n-1]=='\n' ){
+ n--;
+ if( n>0 && zLine[n-1]=='\r' ) n--;
+ zLine[n] = 0;
+ break;
+ }
+ }
+#if defined(_WIN32) || defined(WIN32)
+ /* For interactive input on Windows systems, translate the
+ ** multi-byte characterset characters into UTF-8. */
+ if( stdin_is_interactive && in==stdin ){
+ char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
+ if( zTrans ){
+ int nTrans = strlen30(zTrans)+1;
+ if( nTrans>nLine ){
+ zLine = realloc(zLine, nTrans);
+ if( zLine==0 ){
+ sqlite3_free(zTrans);
+ return 0;
+ }
+ }
+ memcpy(zLine, zTrans, nTrans);
+ sqlite3_free(zTrans);
+ }
+ }
+#endif /* defined(_WIN32) || defined(WIN32) */
+ return zLine;
+}
+
+/*
+** Retrieve a single line of input text.
+**
+** If in==0 then read from standard input and prompt before each line.
+** If isContinuation is true, then a continuation prompt is appropriate.
+** If isContinuation is zero, then the main prompt should be used.
+**
+** If zPrior is not NULL then it is a buffer from a prior call to this
+** routine that can be reused.
+**
+** The result is stored in space obtained from malloc() and must either
+** be freed by the caller or else passed back into this routine via the
+** zPrior argument for reuse.
+*/
+static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
+ char *zPrompt;
+ char *zResult;
+ if( in!=0 ){
+ zResult = local_getline(zPrior, in);
+ }else{
+ zPrompt = isContinuation ? continuePrompt : mainPrompt;
+#if SHELL_USE_LOCAL_GETLINE
+ printf("%s", zPrompt);
+ fflush(stdout);
+ zResult = local_getline(zPrior, stdin);
+#else
+ free(zPrior);
+ zResult = shell_readline(zPrompt);
+ if( zResult && *zResult ) shell_add_history(zResult);
+#endif
+ }
+ return zResult;
+}
+/*
+** A variable length string to which one can append text.
+*/
+typedef struct ShellText ShellText;
+struct ShellText {
+ char *z;
+ int n;
+ int nAlloc;
+};
+
+/*
+** Initialize and destroy a ShellText object
+*/
+static void initText(ShellText *p){
+ memset(p, 0, sizeof(*p));
+}
+static void freeText(ShellText *p){
+ free(p->z);
+ initText(p);
+}
+
+/* zIn is either a pointer to a NULL-terminated string in memory obtained
+** from malloc(), or a NULL pointer. The string pointed to by zAppend is
+** added to zIn, and the result returned in memory obtained from malloc().
+** zIn, if it was not NULL, is freed.
+**
+** If the third argument, quote, is not '\0', then it is used as a
+** quote character for zAppend.
+*/
+static void appendText(ShellText *p, char const *zAppend, char quote){
+ int len;
+ int i;
+ int nAppend = strlen30(zAppend);
+
+ len = nAppend+p->n+1;
+ if( quote ){
+ len += 2;
+ for(i=0; i<nAppend; i++){
+ if( zAppend[i]==quote ) len++;
+ }
+ }
+
+ if( p->n+len>=p->nAlloc ){
+ p->nAlloc = p->nAlloc*2 + len + 20;
+ p->z = realloc(p->z, p->nAlloc);
+ if( p->z==0 ){
+ memset(p, 0, sizeof(*p));
+ return;
+ }
+ }
+
+ if( quote ){
+ char *zCsr = p->z+p->n;
+ *zCsr++ = quote;
+ for(i=0; i<nAppend; i++){
+ *zCsr++ = zAppend[i];
+ if( zAppend[i]==quote ) *zCsr++ = quote;
+ }
+ *zCsr++ = quote;
+ p->n = (int)(zCsr - p->z);
+ *zCsr = '\0';
+ }else{
+ memcpy(p->z+p->n, zAppend, nAppend);
+ p->n += nAppend;
+ p->z[p->n] = '\0';
+ }
+}
+
+/*
+** Attempt to determine if identifier zName needs to be quoted, either
+** because it contains non-alphanumeric characters, or because it is an
+** SQLite keyword. Be conservative in this estimate: When in doubt assume
+** that quoting is required.
+**
+** Return '"' if quoting is required. Return 0 if no quoting is required.
+*/
+static char quoteChar(const char *zName){
+ /* All SQLite keywords, in alphabetical order */
+ static const char *azKeywords[] = {
+ "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS",
+ "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY",
+ "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT",
+ "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE",
+ "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
+ "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH",
+ "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN",
+ "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF",
+ "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER",
+ "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY",
+ "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL",
+ "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA",
+ "PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP",
+ "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT",
+ "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP",
+ "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE",
+ "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE",
+ "WITH", "WITHOUT",
+ };
+ int i, lwr, upr, mid, c;
+ if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
+ for(i=0; zName[i]; i++){
+ if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
+ }
+ lwr = 0;
+ upr = sizeof(azKeywords)/sizeof(azKeywords[0]) - 1;
+ while( lwr<=upr ){
+ mid = (lwr+upr)/2;
+ c = sqlite3_stricmp(azKeywords[mid], zName);
+ if( c==0 ) return '"';
+ if( c<0 ){
+ lwr = mid+1;
+ }else{
+ upr = mid-1;
+ }
+ }
+ return 0;
+}
+
+/*
+** SQL function: shell_add_schema(S,X)
+**
+** Add the schema name X to the CREATE statement in S and return the result.
+** Examples:
+**
+** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x);
+**
+** Also works on
+**
+** CREATE INDEX
+** CREATE UNIQUE INDEX
+** CREATE VIEW
+** CREATE TRIGGER
+** CREATE VIRTUAL TABLE
+**
+** This UDF is used by the .schema command to insert the schema name of
+** attached databases into the middle of the sqlite_master.sql field.
+*/
+static void shellAddSchemaName(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ static const char *aPrefix[] = {
+ "TABLE",
+ "INDEX",
+ "UNIQUE INDEX",
+ "VIEW",
+ "TRIGGER",
+ "VIRTUAL TABLE"
+ };
+ int i = 0;
+ const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
+ const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
+ assert( nVal==2 );
+ if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
+ for(i=0; i<(int)(sizeof(aPrefix)/sizeof(aPrefix[0])); i++){
+ int n = strlen30(aPrefix[i]);
+ if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
+ char cQuote = quoteChar(zSchema);
+ char *z;
+ if( cQuote ){
+ z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
+ }else{
+ z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
+ }
+ sqlite3_result_text(pCtx, z, -1, sqlite3_free);
+ return;
+ }
+ }
+ }
+ sqlite3_result_value(pCtx, apVal[0]);
+}
+
+/*
+** The source code for several run-time loadable extensions is inserted
+** below by the ../tool/mkshellc.tcl script. Before processing that included
+** code, we need to override some macros to make the included program code
+** work here in the middle of this regular program.
+*/
+#define SQLITE_EXTENSION_INIT1
+#define SQLITE_EXTENSION_INIT2(X) (void)(X)
+
+/************************* Begin ../ext/misc/shathree.c ******************/
+/*
+** 2017-03-08
+**
+** 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 SQLite extension implements a functions that compute SHA1 hashes.
+** Two SQL functions are implemented:
+**
+** sha3(X,SIZE)
+** sha3_query(Y,SIZE)
+**
+** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
+** X is NULL.
+**
+** The sha3_query(Y) function evalutes all queries in the SQL statements of Y
+** and returns a hash of their results.
+**
+** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm
+** is used. If SIZE is included it must be one of the integers 224, 256,
+** 384, or 512, to determine SHA3 hash variant that is computed.
+*/
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <stdarg.h>
+typedef sqlite3_uint64 u64;
+
+/******************************************************************************
+** The Hash Engine
+*/
+/*
+** Macros to determine whether the machine is big or little endian,
+** and whether or not that determination is run-time or compile-time.
+**
+** For best performance, an attempt is made to guess at the byte-order
+** using C-preprocessor macros. If that is unsuccessful, or if
+** -DSHA3_BYTEORDER=0 is set, then byte-order is determined
+** at run-time.
+*/
+#ifndef SHA3_BYTEORDER
+# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
+ defined(__arm__)
+# define SHA3_BYTEORDER 1234
+# elif defined(sparc) || defined(__ppc__)
+# define SHA3_BYTEORDER 4321
+# else
+# define SHA3_BYTEORDER 0
+# endif
+#endif
+
+
+/*
+** State structure for a SHA3 hash in progress
+*/
+typedef struct SHA3Context SHA3Context;
+struct SHA3Context {
+ union {
+ u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */
+ unsigned char x[1600]; /* ... or 1600 bytes */
+ } u;
+ unsigned nRate; /* Bytes of input accepted per Keccak iteration */
+ unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */
+ unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
+};
+
+/*
+** A single step of the Keccak mixing function for a 1600-bit state
+*/
+static void KeccakF1600Step(SHA3Context *p){
+ int i;
+ u64 B0, B1, B2, B3, B4;
+ u64 C0, C1, C2, C3, C4;
+ u64 D0, D1, D2, D3, D4;
+ static const u64 RC[] = {
+ 0x0000000000000001ULL, 0x0000000000008082ULL,
+ 0x800000000000808aULL, 0x8000000080008000ULL,
+ 0x000000000000808bULL, 0x0000000080000001ULL,
+ 0x8000000080008081ULL, 0x8000000000008009ULL,
+ 0x000000000000008aULL, 0x0000000000000088ULL,
+ 0x0000000080008009ULL, 0x000000008000000aULL,
+ 0x000000008000808bULL, 0x800000000000008bULL,
+ 0x8000000000008089ULL, 0x8000000000008003ULL,
+ 0x8000000000008002ULL, 0x8000000000000080ULL,
+ 0x000000000000800aULL, 0x800000008000000aULL,
+ 0x8000000080008081ULL, 0x8000000000008080ULL,
+ 0x0000000080000001ULL, 0x8000000080008008ULL
+ };
+# define A00 (p->u.s[0])
+# define A01 (p->u.s[1])
+# define A02 (p->u.s[2])
+# define A03 (p->u.s[3])
+# define A04 (p->u.s[4])
+# define A10 (p->u.s[5])
+# define A11 (p->u.s[6])
+# define A12 (p->u.s[7])
+# define A13 (p->u.s[8])
+# define A14 (p->u.s[9])
+# define A20 (p->u.s[10])
+# define A21 (p->u.s[11])
+# define A22 (p->u.s[12])
+# define A23 (p->u.s[13])
+# define A24 (p->u.s[14])
+# define A30 (p->u.s[15])
+# define A31 (p->u.s[16])
+# define A32 (p->u.s[17])
+# define A33 (p->u.s[18])
+# define A34 (p->u.s[19])
+# define A40 (p->u.s[20])
+# define A41 (p->u.s[21])
+# define A42 (p->u.s[22])
+# define A43 (p->u.s[23])
+# define A44 (p->u.s[24])
+# define ROL64(a,x) ((a<<x)|(a>>(64-x)))
+
+ for(i=0; i<24; i+=4){
+ C0 = A00^A10^A20^A30^A40;
+ C1 = A01^A11^A21^A31^A41;
+ C2 = A02^A12^A22^A32^A42;
+ C3 = A03^A13^A23^A33^A43;
+ C4 = A04^A14^A24^A34^A44;
+ D0 = C4^ROL64(C1, 1);
+ D1 = C0^ROL64(C2, 1);
+ D2 = C1^ROL64(C3, 1);
+ D3 = C2^ROL64(C4, 1);
+ D4 = C3^ROL64(C0, 1);
+
+ B0 = (A00^D0);
+ B1 = ROL64((A11^D1), 44);
+ B2 = ROL64((A22^D2), 43);
+ B3 = ROL64((A33^D3), 21);
+ B4 = ROL64((A44^D4), 14);
+ A00 = B0 ^((~B1)& B2 );
+ A00 ^= RC[i];
+ A11 = B1 ^((~B2)& B3 );
+ A22 = B2 ^((~B3)& B4 );
+ A33 = B3 ^((~B4)& B0 );
+ A44 = B4 ^((~B0)& B1 );
+
+ B2 = ROL64((A20^D0), 3);
+ B3 = ROL64((A31^D1), 45);
+ B4 = ROL64((A42^D2), 61);
+ B0 = ROL64((A03^D3), 28);
+ B1 = ROL64((A14^D4), 20);
+ A20 = B0 ^((~B1)& B2 );
+ A31 = B1 ^((~B2)& B3 );
+ A42 = B2 ^((~B3)& B4 );
+ A03 = B3 ^((~B4)& B0 );
+ A14 = B4 ^((~B0)& B1 );
+
+ B4 = ROL64((A40^D0), 18);
+ B0 = ROL64((A01^D1), 1);
+ B1 = ROL64((A12^D2), 6);
+ B2 = ROL64((A23^D3), 25);
+ B3 = ROL64((A34^D4), 8);
+ A40 = B0 ^((~B1)& B2 );
+ A01 = B1 ^((~B2)& B3 );
+ A12 = B2 ^((~B3)& B4 );
+ A23 = B3 ^((~B4)& B0 );
+ A34 = B4 ^((~B0)& B1 );
+
+ B1 = ROL64((A10^D0), 36);
+ B2 = ROL64((A21^D1), 10);
+ B3 = ROL64((A32^D2), 15);
+ B4 = ROL64((A43^D3), 56);
+ B0 = ROL64((A04^D4), 27);
+ A10 = B0 ^((~B1)& B2 );
+ A21 = B1 ^((~B2)& B3 );
+ A32 = B2 ^((~B3)& B4 );
+ A43 = B3 ^((~B4)& B0 );
+ A04 = B4 ^((~B0)& B1 );
+
+ B3 = ROL64((A30^D0), 41);
+ B4 = ROL64((A41^D1), 2);
+ B0 = ROL64((A02^D2), 62);
+ B1 = ROL64((A13^D3), 55);
+ B2 = ROL64((A24^D4), 39);
+ A30 = B0 ^((~B1)& B2 );
+ A41 = B1 ^((~B2)& B3 );
+ A02 = B2 ^((~B3)& B4 );
+ A13 = B3 ^((~B4)& B0 );
+ A24 = B4 ^((~B0)& B1 );
+
+ C0 = A00^A20^A40^A10^A30;
+ C1 = A11^A31^A01^A21^A41;
+ C2 = A22^A42^A12^A32^A02;
+ C3 = A33^A03^A23^A43^A13;
+ C4 = A44^A14^A34^A04^A24;
+ D0 = C4^ROL64(C1, 1);
+ D1 = C0^ROL64(C2, 1);
+ D2 = C1^ROL64(C3, 1);
+ D3 = C2^ROL64(C4, 1);
+ D4 = C3^ROL64(C0, 1);
+
+ B0 = (A00^D0);
+ B1 = ROL64((A31^D1), 44);
+ B2 = ROL64((A12^D2), 43);
+ B3 = ROL64((A43^D3), 21);
+ B4 = ROL64((A24^D4), 14);
+ A00 = B0 ^((~B1)& B2 );
+ A00 ^= RC[i+1];
+ A31 = B1 ^((~B2)& B3 );
+ A12 = B2 ^((~B3)& B4 );
+ A43 = B3 ^((~B4)& B0 );
+ A24 = B4 ^((~B0)& B1 );
+
+ B2 = ROL64((A40^D0), 3);
+ B3 = ROL64((A21^D1), 45);
+ B4 = ROL64((A02^D2), 61);
+ B0 = ROL64((A33^D3), 28);
+ B1 = ROL64((A14^D4), 20);
+ A40 = B0 ^((~B1)& B2 );
+ A21 = B1 ^((~B2)& B3 );
+ A02 = B2 ^((~B3)& B4 );
+ A33 = B3 ^((~B4)& B0 );
+ A14 = B4 ^((~B0)& B1 );
+
+ B4 = ROL64((A30^D0), 18);
+ B0 = ROL64((A11^D1), 1);
+ B1 = ROL64((A42^D2), 6);
+ B2 = ROL64((A23^D3), 25);
+ B3 = ROL64((A04^D4), 8);
+ A30 = B0 ^((~B1)& B2 );
+ A11 = B1 ^((~B2)& B3 );
+ A42 = B2 ^((~B3)& B4 );
+ A23 = B3 ^((~B4)& B0 );
+ A04 = B4 ^((~B0)& B1 );
+
+ B1 = ROL64((A20^D0), 36);
+ B2 = ROL64((A01^D1), 10);
+ B3 = ROL64((A32^D2), 15);
+ B4 = ROL64((A13^D3), 56);
+ B0 = ROL64((A44^D4), 27);
+ A20 = B0 ^((~B1)& B2 );
+ A01 = B1 ^((~B2)& B3 );
+ A32 = B2 ^((~B3)& B4 );
+ A13 = B3 ^((~B4)& B0 );
+ A44 = B4 ^((~B0)& B1 );
+
+ B3 = ROL64((A10^D0), 41);
+ B4 = ROL64((A41^D1), 2);
+ B0 = ROL64((A22^D2), 62);
+ B1 = ROL64((A03^D3), 55);
+ B2 = ROL64((A34^D4), 39);
+ A10 = B0 ^((~B1)& B2 );
+ A41 = B1 ^((~B2)& B3 );
+ A22 = B2 ^((~B3)& B4 );
+ A03 = B3 ^((~B4)& B0 );
+ A34 = B4 ^((~B0)& B1 );
+
+ C0 = A00^A40^A30^A20^A10;
+ C1 = A31^A21^A11^A01^A41;
+ C2 = A12^A02^A42^A32^A22;
+ C3 = A43^A33^A23^A13^A03;
+ C4 = A24^A14^A04^A44^A34;
+ D0 = C4^ROL64(C1, 1);
+ D1 = C0^ROL64(C2, 1);
+ D2 = C1^ROL64(C3, 1);
+ D3 = C2^ROL64(C4, 1);
+ D4 = C3^ROL64(C0, 1);
+
+ B0 = (A00^D0);
+ B1 = ROL64((A21^D1), 44);
+ B2 = ROL64((A42^D2), 43);
+ B3 = ROL64((A13^D3), 21);
+ B4 = ROL64((A34^D4), 14);
+ A00 = B0 ^((~B1)& B2 );
+ A00 ^= RC[i+2];
+ A21 = B1 ^((~B2)& B3 );
+ A42 = B2 ^((~B3)& B4 );
+ A13 = B3 ^((~B4)& B0 );
+ A34 = B4 ^((~B0)& B1 );
+
+ B2 = ROL64((A30^D0), 3);
+ B3 = ROL64((A01^D1), 45);
+ B4 = ROL64((A22^D2), 61);
+ B0 = ROL64((A43^D3), 28);
+ B1 = ROL64((A14^D4), 20);
+ A30 = B0 ^((~B1)& B2 );
+ A01 = B1 ^((~B2)& B3 );
+ A22 = B2 ^((~B3)& B4 );
+ A43 = B3 ^((~B4)& B0 );
+ A14 = B4 ^((~B0)& B1 );
+
+ B4 = ROL64((A10^D0), 18);
+ B0 = ROL64((A31^D1), 1);
+ B1 = ROL64((A02^D2), 6);
+ B2 = ROL64((A23^D3), 25);
+ B3 = ROL64((A44^D4), 8);
+ A10 = B0 ^((~B1)& B2 );
+ A31 = B1 ^((~B2)& B3 );
+ A02 = B2 ^((~B3)& B4 );
+ A23 = B3 ^((~B4)& B0 );
+ A44 = B4 ^((~B0)& B1 );
+
+ B1 = ROL64((A40^D0), 36);
+ B2 = ROL64((A11^D1), 10);
+ B3 = ROL64((A32^D2), 15);
+ B4 = ROL64((A03^D3), 56);
+ B0 = ROL64((A24^D4), 27);
+ A40 = B0 ^((~B1)& B2 );
+ A11 = B1 ^((~B2)& B3 );
+ A32 = B2 ^((~B3)& B4 );
+ A03 = B3 ^((~B4)& B0 );
+ A24 = B4 ^((~B0)& B1 );
+
+ B3 = ROL64((A20^D0), 41);
+ B4 = ROL64((A41^D1), 2);
+ B0 = ROL64((A12^D2), 62);
+ B1 = ROL64((A33^D3), 55);
+ B2 = ROL64((A04^D4), 39);
+ A20 = B0 ^((~B1)& B2 );
+ A41 = B1 ^((~B2)& B3 );
+ A12 = B2 ^((~B3)& B4 );
+ A33 = B3 ^((~B4)& B0 );
+ A04 = B4 ^((~B0)& B1 );
+
+ C0 = A00^A30^A10^A40^A20;
+ C1 = A21^A01^A31^A11^A41;
+ C2 = A42^A22^A02^A32^A12;
+ C3 = A13^A43^A23^A03^A33;
+ C4 = A34^A14^A44^A24^A04;
+ D0 = C4^ROL64(C1, 1);
+ D1 = C0^ROL64(C2, 1);
+ D2 = C1^ROL64(C3, 1);
+ D3 = C2^ROL64(C4, 1);
+ D4 = C3^ROL64(C0, 1);
+
+ B0 = (A00^D0);
+ B1 = ROL64((A01^D1), 44);
+ B2 = ROL64((A02^D2), 43);
+ B3 = ROL64((A03^D3), 21);
+ B4 = ROL64((A04^D4), 14);
+ A00 = B0 ^((~B1)& B2 );
+ A00 ^= RC[i+3];
+ A01 = B1 ^((~B2)& B3 );
+ A02 = B2 ^((~B3)& B4 );
+ A03 = B3 ^((~B4)& B0 );
+ A04 = B4 ^((~B0)& B1 );
+
+ B2 = ROL64((A10^D0), 3);
+ B3 = ROL64((A11^D1), 45);
+ B4 = ROL64((A12^D2), 61);
+ B0 = ROL64((A13^D3), 28);
+ B1 = ROL64((A14^D4), 20);
+ A10 = B0 ^((~B1)& B2 );
+ A11 = B1 ^((~B2)& B3 );
+ A12 = B2 ^((~B3)& B4 );
+ A13 = B3 ^((~B4)& B0 );
+ A14 = B4 ^((~B0)& B1 );
+
+ B4 = ROL64((A20^D0), 18);
+ B0 = ROL64((A21^D1), 1);
+ B1 = ROL64((A22^D2), 6);
+ B2 = ROL64((A23^D3), 25);
+ B3 = ROL64((A24^D4), 8);
+ A20 = B0 ^((~B1)& B2 );
+ A21 = B1 ^((~B2)& B3 );
+ A22 = B2 ^((~B3)& B4 );
+ A23 = B3 ^((~B4)& B0 );
+ A24 = B4 ^((~B0)& B1 );
+
+ B1 = ROL64((A30^D0), 36);
+ B2 = ROL64((A31^D1), 10);
+ B3 = ROL64((A32^D2), 15);
+ B4 = ROL64((A33^D3), 56);
+ B0 = ROL64((A34^D4), 27);
+ A30 = B0 ^((~B1)& B2 );
+ A31 = B1 ^((~B2)& B3 );
+ A32 = B2 ^((~B3)& B4 );
+ A33 = B3 ^((~B4)& B0 );
+ A34 = B4 ^((~B0)& B1 );
+
+ B3 = ROL64((A40^D0), 41);
+ B4 = ROL64((A41^D1), 2);
+ B0 = ROL64((A42^D2), 62);
+ B1 = ROL64((A43^D3), 55);
+ B2 = ROL64((A44^D4), 39);
+ A40 = B0 ^((~B1)& B2 );
+ A41 = B1 ^((~B2)& B3 );
+ A42 = B2 ^((~B3)& B4 );
+ A43 = B3 ^((~B4)& B0 );
+ A44 = B4 ^((~B0)& B1 );
+ }
+}
+
+/*
+** Initialize a new hash. iSize determines the size of the hash
+** in bits and should be one of 224, 256, 384, or 512. Or iSize
+** can be zero to use the default hash size of 256 bits.
+*/
+static void SHA3Init(SHA3Context *p, int iSize){
+ memset(p, 0, sizeof(*p));
+ if( iSize>=128 && iSize<=512 ){
+ p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
+ }else{
+ p->nRate = (1600 - 2*256)/8;
+ }
+#if SHA3_BYTEORDER==1234
+ /* Known to be little-endian at compile-time. No-op */
+#elif SHA3_BYTEORDER==4321
+ p->ixMask = 7; /* Big-endian */
+#else
+ {
+ static unsigned int one = 1;
+ if( 1==*(unsigned char*)&one ){
+ /* Little endian. No byte swapping. */
+ p->ixMask = 0;
+ }else{
+ /* Big endian. Byte swap. */
+ p->ixMask = 7;
+ }
+ }
+#endif
+}
+
+/*
+** Make consecutive calls to the SHA3Update function to add new content
+** to the hash
+*/
+static void SHA3Update(
+ SHA3Context *p,
+ const unsigned char *aData,
+ unsigned int nData
+){
+ unsigned int i = 0;
+#if SHA3_BYTEORDER==1234
+ if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
+ for(; i+7<nData; i+=8){
+ p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
+ p->nLoaded += 8;
+ if( p->nLoaded>=p->nRate ){
+ KeccakF1600Step(p);
+ p->nLoaded = 0;
+ }
+ }
+ }
+#endif
+ for(; i<nData; i++){
+#if SHA3_BYTEORDER==1234
+ p->u.x[p->nLoaded] ^= aData[i];
+#elif SHA3_BYTEORDER==4321
+ p->u.x[p->nLoaded^0x07] ^= aData[i];
+#else
+ p->u.x[p->nLoaded^p->ixMask] ^= aData[i];
+#endif
+ p->nLoaded++;
+ if( p->nLoaded==p->nRate ){
+ KeccakF1600Step(p);
+ p->nLoaded = 0;
+ }
+ }
+}
+
+/*
+** After all content has been added, invoke SHA3Final() to compute
+** the final hash. The function returns a pointer to the binary
+** hash value.
+*/
+static unsigned char *SHA3Final(SHA3Context *p){
+ unsigned int i;
+ if( p->nLoaded==p->nRate-1 ){
+ const unsigned char c1 = 0x86;
+ SHA3Update(p, &c1, 1);
+ }else{
+ const unsigned char c2 = 0x06;
+ const unsigned char c3 = 0x80;
+ SHA3Update(p, &c2, 1);
+ p->nLoaded = p->nRate - 1;
+ SHA3Update(p, &c3, 1);
+ }
+ for(i=0; i<p->nRate; i++){
+ p->u.x[i+p->nRate] = p->u.x[i^p->ixMask];
+ }
+ return &p->u.x[p->nRate];
+}
+/* End of the hashing logic
+*****************************************************************************/
+
+/*
+** Implementation of the sha3(X,SIZE) function.
+**
+** Return a BLOB which is the SIZE-bit SHA3 hash of X. The default
+** size is 256. If X is a BLOB, it is hashed as is.
+** For all other non-NULL types of input, X is converted into a UTF-8 string
+** and the string is hashed without the trailing 0x00 terminator. The hash
+** of a NULL value is NULL.
+*/
+static void sha3Func(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ SHA3Context cx;
+ int eType = sqlite3_value_type(argv[0]);
+ int nByte = sqlite3_value_bytes(argv[0]);
+ int iSize;
+ if( argc==1 ){
+ iSize = 256;
+ }else{
+ iSize = sqlite3_value_int(argv[1]);
+ if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
+ sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
+ "384 512", -1);
+ return;
+ }
+ }
+ if( eType==SQLITE_NULL ) return;
+ SHA3Init(&cx, iSize);
+ if( eType==SQLITE_BLOB ){
+ SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte);
+ }else{
+ SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte);
+ }
+ sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
+}
+
+/* Compute a string using sqlite3_vsnprintf() with a maximum length
+** of 50 bytes and add it to the hash.
+*/
+static void hash_step_vformat(
+ SHA3Context *p, /* Add content to this context */
+ const char *zFormat,
+ ...
+){
+ va_list ap;
+ int n;
+ char zBuf[50];
+ va_start(ap, zFormat);
+ sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
+ va_end(ap);
+ n = (int)strlen(zBuf);
+ SHA3Update(p, (unsigned char*)zBuf, n);
+}
+
+/*
+** Implementation of the sha3_query(SQL,SIZE) function.
+**
+** This function compiles and runs the SQL statement(s) given in the
+** argument. The results are hashed using a SIZE-bit SHA3. The default
+** size is 256.
+**
+** The format of the byte stream that is hashed is summarized as follows:
+**
+** S<n>:<sql>
+** R
+** N
+** I<int>
+** F<ieee-float>
+** B<size>:<bytes>
+** T<size>:<text>
+**
+** <sql> is the original SQL text for each statement run and <n> is
+** the size of that text. The SQL text is UTF-8. A single R character
+** occurs before the start of each row. N means a NULL value.
+** I mean an 8-byte little-endian integer <int>. F is a floating point
+** number with an 8-byte little-endian IEEE floating point value <ieee-float>.
+** B means blobs of <size> bytes. T means text rendered as <size>
+** bytes of UTF-8. The <n> and <size> values are expressed as an ASCII
+** text integers.
+**
+** For each SQL statement in the X input, there is one S segment. Each
+** S segment is followed by zero or more R segments, one for each row in the
+** result set. After each R, there are one or more N, I, F, B, or T segments,
+** one for each column in the result set. Segments are concatentated directly
+** with no delimiters of any kind.
+*/
+static void sha3QueryFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zSql = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3_stmt *pStmt = 0;
+ int nCol; /* Number of columns in the result set */
+ int i; /* Loop counter */
+ int rc;
+ int n;
+ const char *z;
+ SHA3Context cx;
+ int iSize;
+
+ if( argc==1 ){
+ iSize = 256;
+ }else{
+ iSize = sqlite3_value_int(argv[1]);
+ if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
+ sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
+ "384 512", -1);
+ return;
+ }
+ }
+ if( zSql==0 ) return;
+ SHA3Init(&cx, iSize);
+ while( zSql[0] ){
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
+ if( rc ){
+ char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
+ zSql, sqlite3_errmsg(db));
+ sqlite3_finalize(pStmt);
+ sqlite3_result_error(context, zMsg, -1);
+ sqlite3_free(zMsg);
+ return;
+ }
+ if( !sqlite3_stmt_readonly(pStmt) ){
+ char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
+ sqlite3_finalize(pStmt);
+ sqlite3_result_error(context, zMsg, -1);
+ sqlite3_free(zMsg);
+ return;
+ }
+ nCol = sqlite3_column_count(pStmt);
+ z = sqlite3_sql(pStmt);
+ n = (int)strlen(z);
+ hash_step_vformat(&cx,"S%d:",n);
+ SHA3Update(&cx,(unsigned char*)z,n);
+
+ /* Compute a hash over the result of the query */
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ SHA3Update(&cx,(const unsigned char*)"R",1);
+ for(i=0; i<nCol; i++){
+ switch( sqlite3_column_type(pStmt,i) ){
+ case SQLITE_NULL: {
+ SHA3Update(&cx, (const unsigned char*)"N",1);
+ break;
+ }
+ case SQLITE_INTEGER: {
+ sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
+ memcpy(&u, &v, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'I';
+ SHA3Update(&cx, x, 9);
+ break;
+ }
+ case SQLITE_FLOAT: {
+ sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ double r = sqlite3_column_double(pStmt,i);
+ memcpy(&u, &r, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'F';
+ SHA3Update(&cx,x,9);
+ break;
+ }
+ case SQLITE_TEXT: {
+ int n2 = sqlite3_column_bytes(pStmt, i);
+ const unsigned char *z2 = sqlite3_column_text(pStmt, i);
+ hash_step_vformat(&cx,"T%d:",n2);
+ SHA3Update(&cx, z2, n2);
+ break;
+ }
+ case SQLITE_BLOB: {
+ int n2 = sqlite3_column_bytes(pStmt, i);
+ const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
+ hash_step_vformat(&cx,"B%d:",n2);
+ SHA3Update(&cx, z2, n2);
+ break;
+ }
+ }
+ }
+ }
+ sqlite3_finalize(pStmt);
+ }
+ sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
+}
+
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_shathree_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "sha3", 1, SQLITE_UTF8, 0,
+ sha3Func, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8, 0,
+ sha3Func, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8, 0,
+ sha3QueryFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8, 0,
+ sha3QueryFunc, 0, 0);
+ }
+ return rc;
+}
+
+/************************* End ../ext/misc/shathree.c ********************/
+/************************* Begin ../ext/misc/fileio.c ******************/
+/*
+** 2014-06-13
+**
+** 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 SQLite extension implements SQL functions readfile() and
+** writefile().
+*/
+SQLITE_EXTENSION_INIT1
+#include <stdio.h>
+
+/*
+** Implementation of the "readfile(X)" SQL function. The entire content
+** of the file named X is read and returned as a BLOB. NULL is returned
+** if the file does not exist or is unreadable.
+*/
+static void readfileFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zName;
+ FILE *in;
+ long nIn;
+ void *pBuf;
+
+ (void)(argc); /* Unused parameter */
+ zName = (const char*)sqlite3_value_text(argv[0]);
+ if( zName==0 ) return;
+ in = fopen(zName, "rb");
+ if( in==0 ) return;
+ fseek(in, 0, SEEK_END);
+ nIn = ftell(in);
+ rewind(in);
+ pBuf = sqlite3_malloc( nIn );
+ if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
+ sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
+ }else{
+ sqlite3_free(pBuf);
+ }
+ fclose(in);
+}
+
+/*
+** Implementation of the "writefile(X,Y)" SQL function. The argument Y
+** is written into file X. The number of bytes written is returned. Or
+** NULL is returned if something goes wrong, such as being unable to open
+** file X for writing.
+*/
+static void writefileFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ FILE *out;
+ const char *z;
+ sqlite3_int64 rc;
+ const char *zFile;
+
+ (void)(argc); /* Unused parameter */
+ zFile = (const char*)sqlite3_value_text(argv[0]);
+ if( zFile==0 ) return;
+ out = fopen(zFile, "wb");
+ if( out==0 ) return;
+ z = (const char*)sqlite3_value_blob(argv[1]);
+ if( z==0 ){
+ rc = 0;
+ }else{
+ rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
+ }
+ fclose(out);
+ sqlite3_result_int64(context, rc);
+}
+
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_fileio_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
+ readfileFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
+ writefileFunc, 0, 0);
+ }
+ return rc;
+}
+
+/************************* End ../ext/misc/fileio.c ********************/
+/************************* Begin ../ext/misc/completion.c ******************/
+/*
+** 2017-07-10
+**
+** 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 an eponymous virtual table that returns suggested
+** completions for a partial SQL input.
+**
+** Suggested usage:
+**
+** SELECT DISTINCT candidate COLLATE nocase
+** FROM completion($prefix,$wholeline)
+** ORDER BY 1;
+**
+** The two query parameters are optional. $prefix is the text of the
+** current word being typed and that is to be completed. $wholeline is
+** the complete input line, used for context.
+**
+** The raw completion() table might return the same candidate multiple
+** times, for example if the same column name is used to two or more
+** tables. And the candidates are returned in an arbitrary order. Hence,
+** the DISTINCT and ORDER BY are recommended.
+**
+** This virtual table operates at the speed of human typing, and so there
+** is no attempt to make it fast. Even a slow implementation will be much
+** faster than any human can type.
+**
+*/
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* completion_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a completion virtual table
+*/
+typedef struct completion_vtab completion_vtab;
+struct completion_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this completion vtab */
+};
+
+/* completion_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct completion_cursor completion_cursor;
+struct completion_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this cursor */
+ int nPrefix, nLine; /* Number of bytes in zPrefix and zLine */
+ char *zPrefix; /* The prefix for the word we want to complete */
+ char *zLine; /* The whole that we want to complete */
+ const char *zCurrentRow; /* Current output row */
+ sqlite3_stmt *pStmt; /* Current statement */
+ sqlite3_int64 iRowid; /* The rowid */
+ int ePhase; /* Current phase */
+ int j; /* inter-phase counter */
+};
+
+/* Values for ePhase:
+*/
+#define COMPLETION_FIRST_PHASE 1
+#define COMPLETION_KEYWORDS 1
+#define COMPLETION_PRAGMAS 2
+#define COMPLETION_FUNCTIONS 3
+#define COMPLETION_COLLATIONS 4
+#define COMPLETION_INDEXES 5
+#define COMPLETION_TRIGGERS 6
+#define COMPLETION_DATABASES 7
+#define COMPLETION_TABLES 8
+#define COMPLETION_COLUMNS 9
+#define COMPLETION_MODULES 10
+#define COMPLETION_EOF 11
+
+/*
+** The completionConnect() method is invoked to create a new
+** completion_vtab that describes the completion virtual table.
+**
+** Think of this routine as the constructor for completion_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the completion_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against completion will look like.
+*/
+static int completionConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ completion_vtab *pNew;
+ int rc;
+
+ (void)(pAux); /* Unused parameter */
+ (void)(argc); /* Unused parameter */
+ (void)(argv); /* Unused parameter */
+ (void)(pzErr); /* Unused parameter */
+
+/* Column numbers */
+#define COMPLETION_COLUMN_CANDIDATE 0 /* Suggested completion of the input */
+#define COMPLETION_COLUMN_PREFIX 1 /* Prefix of the word to be completed */
+#define COMPLETION_COLUMN_WHOLELINE 2 /* Entire line seen so far */
+#define COMPLETION_COLUMN_PHASE 3 /* ePhase - used for debugging only */
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x("
+ " candidate TEXT,"
+ " prefix TEXT HIDDEN,"
+ " wholeline TEXT HIDDEN,"
+ " phase INT HIDDEN" /* Used for debugging only */
+ ")");
+ 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;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for completion_cursor objects.
+*/
+static int completionDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new completion_cursor object.
+*/
+static int completionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ completion_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->db = ((completion_vtab*)p)->db;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Reset the completion_cursor.
+*/
+static void completionCursorReset(completion_cursor *pCur){
+ sqlite3_free(pCur->zPrefix); pCur->zPrefix = 0; pCur->nPrefix = 0;
+ sqlite3_free(pCur->zLine); pCur->zLine = 0; pCur->nLine = 0;
+ sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0;
+ pCur->j = 0;
+}
+
+/*
+** Destructor for a completion_cursor.
+*/
+static int completionClose(sqlite3_vtab_cursor *cur){
+ completionCursorReset((completion_cursor*)cur);
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+/*
+** All SQL keywords understood by SQLite
+*/
+static const char *completionKwrds[] = {
+ "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS",
+ "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY",
+ "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT",
+ "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE",
+ "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
+ "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH",
+ "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN",
+ "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF",
+ "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER",
+ "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY",
+ "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL",
+ "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA",
+ "PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP",
+ "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT",
+ "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP",
+ "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE",
+ "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE",
+ "WITH", "WITHOUT",
+};
+#define completionKwCount \
+ (int)(sizeof(completionKwrds)/sizeof(completionKwrds[0]))
+
+/*
+** Advance a completion_cursor to its next row of output.
+**
+** The ->ePhase, ->j, and ->pStmt fields of the completion_cursor object
+** record the current state of the scan. This routine sets ->zCurrentRow
+** to the current row of output and then returns. If no more rows remain,
+** then ->ePhase is set to COMPLETION_EOF which will signal the virtual
+** table that has reached the end of its scan.
+**
+** The current implementation just lists potential identifiers and
+** keywords and filters them by zPrefix. Future enhancements should
+** take zLine into account to try to restrict the set of identifiers and
+** keywords based on what would be legal at the current point of input.
+*/
+static int completionNext(sqlite3_vtab_cursor *cur){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ int eNextPhase = 0; /* Next phase to try if current phase reaches end */
+ int iCol = -1; /* If >=0, step pCur->pStmt and use the i-th column */
+ pCur->iRowid++;
+ while( pCur->ePhase!=COMPLETION_EOF ){
+ switch( pCur->ePhase ){
+ case COMPLETION_KEYWORDS: {
+ if( pCur->j >= completionKwCount ){
+ pCur->zCurrentRow = 0;
+ pCur->ePhase = COMPLETION_DATABASES;
+ }else{
+ pCur->zCurrentRow = completionKwrds[pCur->j++];
+ }
+ iCol = -1;
+ break;
+ }
+ case COMPLETION_DATABASES: {
+ if( pCur->pStmt==0 ){
+ sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1,
+ &pCur->pStmt, 0);
+ }
+ iCol = 1;
+ eNextPhase = COMPLETION_TABLES;
+ break;
+ }
+ case COMPLETION_TABLES: {
+ if( pCur->pStmt==0 ){
+ sqlite3_stmt *pS2;
+ char *zSql = 0;
+ const char *zSep = "";
+ sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
+ while( sqlite3_step(pS2)==SQLITE_ROW ){
+ const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
+ zSql = sqlite3_mprintf(
+ "%z%s"
+ "SELECT name FROM \"%w\".sqlite_master"
+ " WHERE type='table'",
+ zSql, zSep, zDb
+ );
+ if( zSql==0 ) return SQLITE_NOMEM;
+ zSep = " UNION ";
+ }
+ sqlite3_finalize(pS2);
+ sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
+ sqlite3_free(zSql);
+ }
+ iCol = 0;
+ eNextPhase = COMPLETION_COLUMNS;
+ break;
+ }
+ case COMPLETION_COLUMNS: {
+ if( pCur->pStmt==0 ){
+ sqlite3_stmt *pS2;
+ char *zSql = 0;
+ const char *zSep = "";
+ sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
+ while( sqlite3_step(pS2)==SQLITE_ROW ){
+ const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
+ zSql = sqlite3_mprintf(
+ "%z%s"
+ "SELECT pti.name FROM \"%w\".sqlite_master AS sm"
+ " JOIN pragma_table_info(sm.name,%Q) AS pti"
+ " WHERE sm.type='table'",
+ zSql, zSep, zDb, zDb
+ );
+ if( zSql==0 ) return SQLITE_NOMEM;
+ zSep = " UNION ";
+ }
+ sqlite3_finalize(pS2);
+ sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
+ sqlite3_free(zSql);
+ }
+ iCol = 0;
+ eNextPhase = COMPLETION_EOF;
+ break;
+ }
+ }
+ if( iCol<0 ){
+ /* This case is when the phase presets zCurrentRow */
+ if( pCur->zCurrentRow==0 ) continue;
+ }else{
+ if( sqlite3_step(pCur->pStmt)==SQLITE_ROW ){
+ /* Extract the next row of content */
+ pCur->zCurrentRow = (const char*)sqlite3_column_text(pCur->pStmt, iCol);
+ }else{
+ /* When all rows are finished, advance to the next phase */
+ sqlite3_finalize(pCur->pStmt);
+ pCur->pStmt = 0;
+ pCur->ePhase = eNextPhase;
+ continue;
+ }
+ }
+ if( pCur->nPrefix==0 ) break;
+ if( sqlite3_strnicmp(pCur->zPrefix, pCur->zCurrentRow, pCur->nPrefix)==0 ){
+ break;
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the completion_cursor
+** is currently pointing.
+*/
+static int completionColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ switch( i ){
+ case COMPLETION_COLUMN_CANDIDATE: {
+ sqlite3_result_text(ctx, pCur->zCurrentRow, -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case COMPLETION_COLUMN_PREFIX: {
+ sqlite3_result_text(ctx, pCur->zPrefix, -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case COMPLETION_COLUMN_WHOLELINE: {
+ sqlite3_result_text(ctx, pCur->zLine, -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case COMPLETION_COLUMN_PHASE: {
+ sqlite3_result_int(ctx, pCur->ePhase);
+ 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 completionRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int completionEof(sqlite3_vtab_cursor *cur){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ return pCur->ePhase >= COMPLETION_EOF;
+}
+
+/*
+** This method is called to "rewind" the completion_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to completionColumn() or completionRowid() or
+** completionEof().
+*/
+static int completionFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ completion_cursor *pCur = (completion_cursor *)pVtabCursor;
+ int iArg = 0;
+ (void)(idxStr); /* Unused parameter */
+ (void)(argc); /* Unused parameter */
+ completionCursorReset(pCur);
+ if( idxNum & 1 ){
+ pCur->nPrefix = sqlite3_value_bytes(argv[iArg]);
+ if( pCur->nPrefix>0 ){
+ pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
+ if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
+ }
+ iArg++;
+ }
+ if( idxNum & 2 ){
+ pCur->nLine = sqlite3_value_bytes(argv[iArg]);
+ if( pCur->nLine>0 ){
+ pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
+ if( pCur->zLine==0 ) return SQLITE_NOMEM;
+ }
+ iArg++;
+ }
+ if( pCur->zLine!=0 && pCur->zPrefix==0 ){
+ int i = pCur->nLine;
+ while( i>0 && (isalnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){
+ i--;
+ }
+ pCur->nPrefix = pCur->nLine - i;
+ if( pCur->nPrefix>0 ){
+ pCur->zPrefix = sqlite3_mprintf("%.*s", pCur->nPrefix, pCur->zLine + i);
+ if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
+ }
+ }
+ pCur->iRowid = 0;
+ pCur->ePhase = COMPLETION_FIRST_PHASE;
+ return completionNext(pVtabCursor);
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the completion virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+**
+** There are two hidden parameters that act as arguments to the table-valued
+** function: "prefix" and "wholeline". Bit 0 of idxNum is set if "prefix"
+** is available and bit 1 is set if "wholeline" is available.
+*/
+static int completionBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i; /* Loop over constraints */
+ int idxNum = 0; /* The query plan bitmask */
+ int prefixIdx = -1; /* Index of the start= constraint, or -1 if none */
+ int wholelineIdx = -1; /* Index of the stop= constraint, or -1 if none */
+ int nArg = 0; /* Number of arguments that completeFilter() expects */
+ const struct sqlite3_index_constraint *pConstraint;
+
+ (void)(tab); /* Unused parameter */
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->usable==0 ) continue;
+ if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ switch( pConstraint->iColumn ){
+ case COMPLETION_COLUMN_PREFIX:
+ prefixIdx = i;
+ idxNum |= 1;
+ break;
+ case COMPLETION_COLUMN_WHOLELINE:
+ wholelineIdx = i;
+ idxNum |= 2;
+ break;
+ }
+ }
+ if( prefixIdx>=0 ){
+ pIdxInfo->aConstraintUsage[prefixIdx].argvIndex = ++nArg;
+ pIdxInfo->aConstraintUsage[prefixIdx].omit = 1;
+ }
+ if( wholelineIdx>=0 ){
+ pIdxInfo->aConstraintUsage[wholelineIdx].argvIndex = ++nArg;
+ pIdxInfo->aConstraintUsage[wholelineIdx].omit = 1;
+ }
+ pIdxInfo->idxNum = idxNum;
+ pIdxInfo->estimatedCost = (double)5000 - 1000*nArg;
+ pIdxInfo->estimatedRows = 500 - 100*nArg;
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** completion virtual table.
+*/
+static sqlite3_module completionModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ completionConnect, /* xConnect */
+ completionBestIndex, /* xBestIndex */
+ completionDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ completionOpen, /* xOpen - open a cursor */
+ completionClose, /* xClose - close a cursor */
+ completionFilter, /* xFilter - configure scan constraints */
+ completionNext, /* xNext - advance a cursor */
+ completionEof, /* xEof - check for end of scan */
+ completionColumn, /* xColumn - read data */
+ completionRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0 /* xRollbackTo */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+int sqlite3CompletionVtabInit(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "completion", &completionModule, 0);
+#endif
+ return rc;
+}
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_completion_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)(pzErrMsg); /* Unused parameter */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3CompletionVtabInit(db);
+#endif
+ return rc;
+}
+
+/************************* End ../ext/misc/completion.c ********************/
+
+#if defined(SQLITE_ENABLE_SESSION)
+/*
+** State information for a single open session
+*/
+typedef struct OpenSession OpenSession;
+struct OpenSession {
+ char *zName; /* Symbolic name for this session */
+ int nFilter; /* Number of xFilter rejection GLOB patterns */
+ char **azFilter; /* Array of xFilter rejection GLOB patterns */
+ sqlite3_session *p; /* The open session */
+};
+#endif
+
+/*
+** Shell output mode information from before ".explain on",
+** saved so that it can be restored by ".explain off"
+*/
+typedef struct SavedModeInfo SavedModeInfo;
+struct SavedModeInfo {
+ int valid; /* Is there legit data in here? */
+ int mode; /* Mode prior to ".explain on" */
+ int showHeader; /* The ".header" setting prior to ".explain on" */
+ int colWidth[100]; /* Column widths prior to ".explain on" */
+};
+
+/*
+** State information about the database connection is contained in an
+** instance of the following structure.
+*/
+typedef struct ShellState ShellState;
+struct ShellState {
+ sqlite3 *db; /* The database */
+ int autoExplain; /* Automatically turn on .explain mode */
+ int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
+ int statsOn; /* True to display memory stats before each finalize */
+ int scanstatsOn; /* True to display scan stats before each finalize */
+ int outCount; /* Revert to stdout when reaching zero */
+ int cnt; /* Number of records displayed so far */
+ FILE *out; /* Write results here */
+ FILE *traceOut; /* Output for sqlite3_trace() */
+ int nErr; /* Number of errors seen */
+ int mode; /* An output mode setting */
+ int cMode; /* temporary output mode for the current query */
+ int normalMode; /* Output mode before ".explain on" */
+ int writableSchema; /* True if PRAGMA writable_schema=ON */
+ int showHeader; /* True to show column names in List or Column mode */
+ int nCheck; /* Number of ".check" commands run */
+ unsigned shellFlgs; /* Various flags */
+ char *zDestTable; /* Name of destination table when MODE_Insert */
+ char zTestcase[30]; /* Name of current test case */
+ char colSeparator[20]; /* Column separator character for several modes */
+ char rowSeparator[20]; /* Row separator character for MODE_Ascii */
+ int colWidth[100]; /* Requested width of each column when in column mode*/
+ int actualWidth[100]; /* Actual width of each column */
+ char nullValue[20]; /* The text to print when a NULL comes back from
+ ** the database */
+ char outfile[FILENAME_MAX]; /* Filename for *out */
+ const char *zDbFilename; /* name of the database file */
+ char *zFreeOnClose; /* Filename to free when closing */
+ const char *zVfs; /* Name of VFS to use */
+ sqlite3_stmt *pStmt; /* Current statement if any. */
+ FILE *pLog; /* Write log output here */
+ int *aiIndent; /* Array of indents used in MODE_Explain */
+ int nIndent; /* Size of array aiIndent[] */
+ int iIndent; /* Index of current op in aiIndent[] */
+#if defined(SQLITE_ENABLE_SESSION)
+ int nSession; /* Number of active sessions */
+ OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */
+#endif
+};
+
+/*
+** These are the allowed shellFlgs values
+*/
+#define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
+#define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
+#define SHFLG_Backslash 0x00000004 /* The --backslash option is used */
+#define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */
+#define SHFLG_Newlines 0x00000010 /* .dump --newline flag */
+#define SHFLG_CountChanges 0x00000020 /* .changes setting */
+#define SHFLG_Echo 0x00000040 /* .echo or --echo setting */
+
+/*
+** Macros for testing and setting shellFlgs
+*/
+#define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0)
+#define ShellSetFlag(P,X) ((P)->shellFlgs|=(X))
+#define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X)))
+
+/*
+** These are the allowed modes.
+*/
+#define MODE_Line 0 /* One column per line. Blank line between records */
+#define MODE_Column 1 /* One record per line in neat columns */
+#define MODE_List 2 /* One record per line with a separator */
+#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
+#define MODE_Html 4 /* Generate an XHTML table */
+#define MODE_Insert 5 /* Generate SQL "insert" statements */
+#define MODE_Quote 6 /* Quote values as for SQL */
+#define MODE_Tcl 7 /* Generate ANSI-C or TCL quoted elements */
+#define MODE_Csv 8 /* Quote strings, numbers are plain */
+#define MODE_Explain 9 /* Like MODE_Column, but do not truncate data */
+#define MODE_Ascii 10 /* Use ASCII unit and record separators (0x1F/0x1E) */
+#define MODE_Pretty 11 /* Pretty-print schemas */
+
+static const char *modeDescr[] = {
+ "line",
+ "column",
+ "list",
+ "semi",
+ "html",
+ "insert",
+ "quote",
+ "tcl",
+ "csv",
+ "explain",
+ "ascii",
+ "prettyprint",
+};
+
+/*
+** These are the column/row/line separators used by the various
+** import/export modes.
+*/
+#define SEP_Column "|"
+#define SEP_Row "\n"
+#define SEP_Tab "\t"
+#define SEP_Space " "
+#define SEP_Comma ","
+#define SEP_CrLf "\r\n"
+#define SEP_Unit "\x1F"
+#define SEP_Record "\x1E"
+
+/*
+** Number of elements in an array
+*/
+#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
+
+/*
+** A callback for the sqlite3_log() interface.
+*/
+static void shellLog(void *pArg, int iErrCode, const char *zMsg){
+ ShellState *p = (ShellState*)pArg;
+ if( p->pLog==0 ) return;
+ utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
+ fflush(p->pLog);
+}
+
+/*
+** Output the given string as a hex-encoded blob (eg. X'1234' )
+*/
+static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
+ int i;
+ char *zBlob = (char *)pBlob;
+ raw_printf(out,"X'");
+ for(i=0; i<nBlob; i++){ raw_printf(out,"%02x",zBlob[i]&0xff); }
+ raw_printf(out,"'");
+}
+
+/*
+** Find a string that is not found anywhere in z[]. Return a pointer
+** to that string.
+**
+** Try to use zA and zB first. If both of those are already found in z[]
+** then make up some string and store it in the buffer zBuf.
+*/
+static const char *unused_string(
+ const char *z, /* Result must not appear anywhere in z */
+ const char *zA, const char *zB, /* Try these first */
+ char *zBuf /* Space to store a generated string */
+){
+ unsigned i = 0;
+ if( strstr(z, zA)==0 ) return zA;
+ if( strstr(z, zB)==0 ) return zB;
+ do{
+ sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
+ }while( strstr(z,zBuf)!=0 );
+ return zBuf;
+}
+
+/*
+** Output the given string as a quoted string using SQL quoting conventions.
+**
+** See also: output_quoted_escaped_string()
+*/
+static void output_quoted_string(FILE *out, const char *z){
+ int i;
+ char c;
+ setBinaryMode(out, 1);
+ for(i=0; (c = z[i])!=0 && c!='\''; i++){}
+ if( c==0 ){
+ utf8_printf(out,"'%s'",z);
+ }else{
+ raw_printf(out, "'");
+ while( *z ){
+ for(i=0; (c = z[i])!=0 && c!='\''; i++){}
+ if( c=='\'' ) i++;
+ if( i ){
+ utf8_printf(out, "%.*s", i, z);
+ z += i;
+ }
+ if( c=='\'' ){
+ raw_printf(out, "'");
+ continue;
+ }
+ if( c==0 ){
+ break;
+ }
+ z++;
+ }
+ raw_printf(out, "'");
+ }
+ setTextMode(out, 1);
+}
+
+/*
+** Output the given string as a quoted string using SQL quoting conventions.
+** Additionallly , escape the "\n" and "\r" characters so that they do not
+** get corrupted by end-of-line translation facilities in some operating
+** systems.
+**
+** This is like output_quoted_string() but with the addition of the \r\n
+** escape mechanism.
+*/
+static void output_quoted_escaped_string(FILE *out, const char *z){
+ int i;
+ char c;
+ setBinaryMode(out, 1);
+ for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
+ if( c==0 ){
+ utf8_printf(out,"'%s'",z);
+ }else{
+ const char *zNL = 0;
+ const char *zCR = 0;
+ int nNL = 0;
+ int nCR = 0;
+ char zBuf1[20], zBuf2[20];
+ for(i=0; z[i]; i++){
+ if( z[i]=='\n' ) nNL++;
+ if( z[i]=='\r' ) nCR++;
+ }
+ if( nNL ){
+ raw_printf(out, "replace(");
+ zNL = unused_string(z, "\\n", "\\012", zBuf1);
+ }
+ if( nCR ){
+ raw_printf(out, "replace(");
+ zCR = unused_string(z, "\\r", "\\015", zBuf2);
+ }
+ raw_printf(out, "'");
+ while( *z ){
+ for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
+ if( c=='\'' ) i++;
+ if( i ){
+ utf8_printf(out, "%.*s", i, z);
+ z += i;
+ }
+ if( c=='\'' ){
+ raw_printf(out, "'");
+ continue;
+ }
+ if( c==0 ){
+ break;
+ }
+ z++;
+ if( c=='\n' ){
+ raw_printf(out, "%s", zNL);
+ continue;
+ }
+ raw_printf(out, "%s", zCR);
+ }
+ raw_printf(out, "'");
+ if( nCR ){
+ raw_printf(out, ",'%s',char(13))", zCR);
+ }
+ if( nNL ){
+ raw_printf(out, ",'%s',char(10))", zNL);
+ }
+ }
+ setTextMode(out, 1);
+}
+
+/*
+** Output the given string as a quoted according to C or TCL quoting rules.
+*/
+static void output_c_string(FILE *out, const char *z){
+ unsigned int c;
+ fputc('"', out);
+ while( (c = *(z++))!=0 ){
+ if( c=='\\' ){
+ fputc(c, out);
+ fputc(c, out);
+ }else if( c=='"' ){
+ fputc('\\', out);
+ fputc('"', out);
+ }else if( c=='\t' ){
+ fputc('\\', out);
+ fputc('t', out);
+ }else if( c=='\n' ){
+ fputc('\\', out);
+ fputc('n', out);
+ }else if( c=='\r' ){
+ fputc('\\', out);
+ fputc('r', out);
+ }else if( !isprint(c&0xff) ){
+ raw_printf(out, "\\%03o", c&0xff);
+ }else{
+ fputc(c, out);
+ }
+ }
+ fputc('"', out);
+}
+
+/*
+** Output the given string with characters that are special to
+** HTML escaped.
+*/
+static void output_html_string(FILE *out, const char *z){
+ int i;
+ if( z==0 ) z = "";
+ while( *z ){
+ for(i=0; z[i]
+ && z[i]!='<'
+ && z[i]!='&'
+ && z[i]!='>'
+ && z[i]!='\"'
+ && z[i]!='\'';
+ i++){}
+ if( i>0 ){
+ utf8_printf(out,"%.*s",i,z);
+ }
+ if( z[i]=='<' ){
+ raw_printf(out,"&lt;");
+ }else if( z[i]=='&' ){
+ raw_printf(out,"&amp;");
+ }else if( z[i]=='>' ){
+ raw_printf(out,"&gt;");
+ }else if( z[i]=='\"' ){
+ raw_printf(out,"&quot;");
+ }else if( z[i]=='\'' ){
+ raw_printf(out,"&#39;");
+ }else{
+ break;
+ }
+ z += i + 1;
+ }
+}
+
+/*
+** If a field contains any character identified by a 1 in the following
+** array, then the string must be quoted for CSV.
+*/
+static const char needCsvQuote[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+/*
+** Output a single term of CSV. Actually, p->colSeparator is used for
+** the separator, which may or may not be a comma. p->nullValue is
+** the null value. Strings are quoted if necessary. The separator
+** is only issued if bSep is true.
+*/
+static void output_csv(ShellState *p, const char *z, int bSep){
+ FILE *out = p->out;
+ if( z==0 ){
+ utf8_printf(out,"%s",p->nullValue);
+ }else{
+ int i;
+ int nSep = strlen30(p->colSeparator);
+ for(i=0; z[i]; i++){
+ if( needCsvQuote[((unsigned char*)z)[i]]
+ || (z[i]==p->colSeparator[0] &&
+ (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
+ i = 0;
+ break;
+ }
+ }
+ if( i==0 ){
+ putc('"', out);
+ for(i=0; z[i]; i++){
+ if( z[i]=='"' ) putc('"', out);
+ putc(z[i], out);
+ }
+ putc('"', out);
+ }else{
+ utf8_printf(out, "%s", z);
+ }
+ }
+ if( bSep ){
+ utf8_printf(p->out, "%s", p->colSeparator);
+ }
+}
+
+#ifdef SIGINT
+/*
+** This routine runs when the user presses Ctrl-C
+*/
+static void interrupt_handler(int NotUsed){
+ UNUSED_PARAMETER(NotUsed);
+ seenInterrupt++;
+ if( seenInterrupt>2 ) exit(1);
+ if( globalDb ) sqlite3_interrupt(globalDb);
+}
+#endif
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+/*
+** When the ".auth ON" is set, the following authorizer callback is
+** invoked. It always returns SQLITE_OK.
+*/
+static int shellAuth(
+ void *pClientData,
+ int op,
+ const char *zA1,
+ const char *zA2,
+ const char *zA3,
+ const char *zA4
+){
+ ShellState *p = (ShellState*)pClientData;
+ static const char *azAction[] = { 0,
+ "CREATE_INDEX", "CREATE_TABLE", "CREATE_TEMP_INDEX",
+ "CREATE_TEMP_TABLE", "CREATE_TEMP_TRIGGER", "CREATE_TEMP_VIEW",
+ "CREATE_TRIGGER", "CREATE_VIEW", "DELETE",
+ "DROP_INDEX", "DROP_TABLE", "DROP_TEMP_INDEX",
+ "DROP_TEMP_TABLE", "DROP_TEMP_TRIGGER", "DROP_TEMP_VIEW",
+ "DROP_TRIGGER", "DROP_VIEW", "INSERT",
+ "PRAGMA", "READ", "SELECT",
+ "TRANSACTION", "UPDATE", "ATTACH",
+ "DETACH", "ALTER_TABLE", "REINDEX",
+ "ANALYZE", "CREATE_VTABLE", "DROP_VTABLE",
+ "FUNCTION", "SAVEPOINT", "RECURSIVE"
+ };
+ int i;
+ const char *az[4];
+ az[0] = zA1;
+ az[1] = zA2;
+ az[2] = zA3;
+ az[3] = zA4;
+ utf8_printf(p->out, "authorizer: %s", azAction[op]);
+ for(i=0; i<4; i++){
+ raw_printf(p->out, " ");
+ if( az[i] ){
+ output_c_string(p->out, az[i]);
+ }else{
+ raw_printf(p->out, "NULL");
+ }
+ }
+ raw_printf(p->out, "\n");
+ return SQLITE_OK;
+}
+#endif
+
+/*
+** Print a schema statement. Part of MODE_Semi and MODE_Pretty output.
+**
+** This routine converts some CREATE TABLE statements for shadow tables
+** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements.
+*/
+static void printSchemaLine(FILE *out, const char *z, const char *zTail){
+ if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
+ utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
+ }else{
+ utf8_printf(out, "%s%s", z, zTail);
+ }
+}
+static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
+ char c = z[n];
+ z[n] = 0;
+ printSchemaLine(out, z, zTail);
+ z[n] = c;
+}
+
+/*
+** This is the callback routine that the shell
+** invokes for each row of a query result.
+*/
+static int shell_callback(
+ void *pArg,
+ int nArg, /* Number of result columns */
+ char **azArg, /* Text of each result column */
+ char **azCol, /* Column names */
+ int *aiType /* Column types */
+){
+ int i;
+ ShellState *p = (ShellState*)pArg;
+
+ if( azArg==0 ) return 0;
+ switch( p->cMode ){
+ case MODE_Line: {
+ int w = 5;
+ if( azArg==0 ) break;
+ for(i=0; i<nArg; i++){
+ int len = strlen30(azCol[i] ? azCol[i] : "");
+ if( len>w ) w = len;
+ }
+ if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator);
+ for(i=0; i<nArg; i++){
+ utf8_printf(p->out,"%*s = %s%s", w, azCol[i],
+ azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
+ }
+ break;
+ }
+ case MODE_Explain:
+ case MODE_Column: {
+ static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
+ const int *colWidth;
+ int showHdr;
+ char *rowSep;
+ if( p->cMode==MODE_Column ){
+ colWidth = p->colWidth;
+ showHdr = p->showHeader;
+ rowSep = p->rowSeparator;
+ }else{
+ colWidth = aExplainWidths;
+ showHdr = 1;
+ rowSep = SEP_Row;
+ }
+ if( p->cnt++==0 ){
+ for(i=0; i<nArg; i++){
+ int w, n;
+ if( i<ArraySize(p->colWidth) ){
+ w = colWidth[i];
+ }else{
+ w = 0;
+ }
+ if( w==0 ){
+ w = strlenChar(azCol[i] ? azCol[i] : "");
+ if( w<10 ) w = 10;
+ n = strlenChar(azArg && azArg[i] ? azArg[i] : p->nullValue);
+ if( w<n ) w = n;
+ }
+ if( i<ArraySize(p->actualWidth) ){
+ p->actualWidth[i] = w;
+ }
+ if( showHdr ){
+ utf8_width_print(p->out, w, azCol[i]);
+ utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
+ }
+ }
+ if( showHdr ){
+ for(i=0; i<nArg; i++){
+ int w;
+ if( i<ArraySize(p->actualWidth) ){
+ w = p->actualWidth[i];
+ if( w<0 ) w = -w;
+ }else{
+ w = 10;
+ }
+ utf8_printf(p->out,"%-*.*s%s",w,w,
+ "----------------------------------------------------------"
+ "----------------------------------------------------------",
+ i==nArg-1 ? rowSep : " ");
+ }
+ }
+ }
+ if( azArg==0 ) break;
+ for(i=0; i<nArg; i++){
+ int w;
+ if( i<ArraySize(p->actualWidth) ){
+ w = p->actualWidth[i];
+ }else{
+ w = 10;
+ }
+ if( p->cMode==MODE_Explain && azArg[i] && strlenChar(azArg[i])>w ){
+ w = strlenChar(azArg[i]);
+ }
+ if( i==1 && p->aiIndent && p->pStmt ){
+ if( p->iIndent<p->nIndent ){
+ utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
+ }
+ p->iIndent++;
+ }
+ utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
+ utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
+ }
+ break;
+ }
+ case MODE_Semi: { /* .schema and .fullschema output */
+ printSchemaLine(p->out, azArg[0], ";\n");
+ break;
+ }
+ case MODE_Pretty: { /* .schema and .fullschema with --indent */
+ char *z;
+ int j;
+ int nParen = 0;
+ char cEnd = 0;
+ char c;
+ int nLine = 0;
+ assert( nArg==1 );
+ if( azArg[0]==0 ) break;
+ if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
+ || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
+ ){
+ utf8_printf(p->out, "%s;\n", azArg[0]);
+ break;
+ }
+ z = sqlite3_mprintf("%s", azArg[0]);
+ j = 0;
+ for(i=0; IsSpace(z[i]); i++){}
+ for(; (c = z[i])!=0; i++){
+ if( IsSpace(c) ){
+ if( z[j-1]=='\r' ) z[j-1] = '\n';
+ if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
+ }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
+ j--;
+ }
+ z[j++] = c;
+ }
+ while( j>0 && IsSpace(z[j-1]) ){ j--; }
+ z[j] = 0;
+ if( strlen30(z)>=79 ){
+ for(i=j=0; (c = z[i])!=0; i++){
+ if( c==cEnd ){
+ cEnd = 0;
+ }else if( c=='"' || c=='\'' || c=='`' ){
+ cEnd = c;
+ }else if( c=='[' ){
+ cEnd = ']';
+ }else if( c=='(' ){
+ nParen++;
+ }else if( c==')' ){
+ nParen--;
+ if( nLine>0 && nParen==0 && j>0 ){
+ printSchemaLineN(p->out, z, j, "\n");
+ j = 0;
+ }
+ }
+ z[j++] = c;
+ if( nParen==1 && (c=='(' || c==',' || c=='\n') ){
+ if( c=='\n' ) j--;
+ printSchemaLineN(p->out, z, j, "\n ");
+ j = 0;
+ nLine++;
+ while( IsSpace(z[i+1]) ){ i++; }
+ }
+ }
+ z[j] = 0;
+ }
+ printSchemaLine(p->out, z, ";\n");
+ sqlite3_free(z);
+ break;
+ }
+ case MODE_List: {
+ if( p->cnt++==0 && p->showHeader ){
+ for(i=0; i<nArg; i++){
+ utf8_printf(p->out,"%s%s",azCol[i],
+ i==nArg-1 ? p->rowSeparator : p->colSeparator);
+ }
+ }
+ if( azArg==0 ) break;
+ for(i=0; i<nArg; i++){
+ char *z = azArg[i];
+ if( z==0 ) z = p->nullValue;
+ utf8_printf(p->out, "%s", z);
+ if( i<nArg-1 ){
+ utf8_printf(p->out, "%s", p->colSeparator);
+ }else{
+ utf8_printf(p->out, "%s", p->rowSeparator);
+ }
+ }
+ break;
+ }
+ case MODE_Html: {
+ if( p->cnt++==0 && p->showHeader ){
+ raw_printf(p->out,"<TR>");
+ for(i=0; i<nArg; i++){
+ raw_printf(p->out,"<TH>");
+ output_html_string(p->out, azCol[i]);
+ raw_printf(p->out,"</TH>\n");
+ }
+ raw_printf(p->out,"</TR>\n");
+ }
+ if( azArg==0 ) break;
+ raw_printf(p->out,"<TR>");
+ for(i=0; i<nArg; i++){
+ raw_printf(p->out,"<TD>");
+ output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
+ raw_printf(p->out,"</TD>\n");
+ }
+ raw_printf(p->out,"</TR>\n");
+ break;
+ }
+ case MODE_Tcl: {
+ if( p->cnt++==0 && p->showHeader ){
+ for(i=0; i<nArg; i++){
+ output_c_string(p->out,azCol[i] ? azCol[i] : "");
+ if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
+ }
+ utf8_printf(p->out, "%s", p->rowSeparator);
+ }
+ if( azArg==0 ) break;
+ for(i=0; i<nArg; i++){
+ output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
+ if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
+ }
+ utf8_printf(p->out, "%s", p->rowSeparator);
+ break;
+ }
+ case MODE_Csv: {
+ setBinaryMode(p->out, 1);
+ if( p->cnt++==0 && p->showHeader ){
+ for(i=0; i<nArg; i++){
+ output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
+ }
+ utf8_printf(p->out, "%s", p->rowSeparator);
+ }
+ if( nArg>0 ){
+ for(i=0; i<nArg; i++){
+ output_csv(p, azArg[i], i<nArg-1);
+ }
+ utf8_printf(p->out, "%s", p->rowSeparator);
+ }
+ setTextMode(p->out, 1);
+ break;
+ }
+ case MODE_Insert: {
+ if( azArg==0 ) break;
+ utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
+ if( p->showHeader ){
+ raw_printf(p->out,"(");
+ for(i=0; i<nArg; i++){
+ if( i>0 ) raw_printf(p->out, ",");
+ if( quoteChar(azCol[i]) ){
+ char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
+ utf8_printf(p->out, "%s", z);
+ sqlite3_free(z);
+ }else{
+ raw_printf(p->out, "%s", azCol[i]);
+ }
+ }
+ raw_printf(p->out,")");
+ }
+ p->cnt++;
+ for(i=0; i<nArg; i++){
+ raw_printf(p->out, i>0 ? "," : " VALUES(");
+ if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
+ utf8_printf(p->out,"NULL");
+ }else if( aiType && aiType[i]==SQLITE_TEXT ){
+ if( ShellHasFlag(p, SHFLG_Newlines) ){
+ output_quoted_string(p->out, azArg[i]);
+ }else{
+ output_quoted_escaped_string(p->out, azArg[i]);
+ }
+ }else if( aiType && aiType[i]==SQLITE_INTEGER ){
+ utf8_printf(p->out,"%s", azArg[i]);
+ }else if( aiType && aiType[i]==SQLITE_FLOAT ){
+ char z[50];
+ double r = sqlite3_column_double(p->pStmt, i);
+ sqlite3_snprintf(50,z,"%!.20g", r);
+ raw_printf(p->out, "%s", z);
+ }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
+ const void *pBlob = sqlite3_column_blob(p->pStmt, i);
+ int nBlob = sqlite3_column_bytes(p->pStmt, i);
+ output_hex_blob(p->out, pBlob, nBlob);
+ }else if( isNumber(azArg[i], 0) ){
+ utf8_printf(p->out,"%s", azArg[i]);
+ }else if( ShellHasFlag(p, SHFLG_Newlines) ){
+ output_quoted_string(p->out, azArg[i]);
+ }else{
+ output_quoted_escaped_string(p->out, azArg[i]);
+ }
+ }
+ raw_printf(p->out,");\n");
+ break;
+ }
+ case MODE_Quote: {
+ if( azArg==0 ) break;
+ if( p->cnt==0 && p->showHeader ){
+ for(i=0; i<nArg; i++){
+ if( i>0 ) raw_printf(p->out, ",");
+ output_quoted_string(p->out, azCol[i]);
+ }
+ raw_printf(p->out,"\n");
+ }
+ p->cnt++;
+ for(i=0; i<nArg; i++){
+ if( i>0 ) raw_printf(p->out, ",");
+ if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
+ utf8_printf(p->out,"NULL");
+ }else if( aiType && aiType[i]==SQLITE_TEXT ){
+ output_quoted_string(p->out, azArg[i]);
+ }else if( aiType && aiType[i]==SQLITE_INTEGER ){
+ utf8_printf(p->out,"%s", azArg[i]);
+ }else if( aiType && aiType[i]==SQLITE_FLOAT ){
+ char z[50];
+ double r = sqlite3_column_double(p->pStmt, i);
+ sqlite3_snprintf(50,z,"%!.20g", r);
+ raw_printf(p->out, "%s", z);
+ }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
+ const void *pBlob = sqlite3_column_blob(p->pStmt, i);
+ int nBlob = sqlite3_column_bytes(p->pStmt, i);
+ output_hex_blob(p->out, pBlob, nBlob);
+ }else if( isNumber(azArg[i], 0) ){
+ utf8_printf(p->out,"%s", azArg[i]);
+ }else{
+ output_quoted_string(p->out, azArg[i]);
+ }
+ }
+ raw_printf(p->out,"\n");
+ break;
+ }
+ case MODE_Ascii: {
+ if( p->cnt++==0 && p->showHeader ){
+ for(i=0; i<nArg; i++){
+ if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
+ utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : "");
+ }
+ utf8_printf(p->out, "%s", p->rowSeparator);
+ }
+ if( azArg==0 ) break;
+ for(i=0; i<nArg; i++){
+ if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
+ utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
+ }
+ utf8_printf(p->out, "%s", p->rowSeparator);
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+** This is the callback routine that the SQLite library
+** invokes for each row of a query result.
+*/
+static int callback(void *pArg, int nArg, char **azArg, char **azCol){
+ /* since we don't have type info, call the shell_callback with a NULL value */
+ return shell_callback(pArg, nArg, azArg, azCol, NULL);
+}
+
+/*
+** This is the callback routine from sqlite3_exec() that appends all
+** output onto the end of a ShellText object.
+*/
+static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){
+ ShellText *p = (ShellText*)pArg;
+ int i;
+ UNUSED_PARAMETER(az);
+ if( azArg==0 ) return 0;
+ if( p->n ) appendText(p, "|", 0);
+ for(i=0; i<nArg; i++){
+ if( i ) appendText(p, ",", 0);
+ if( azArg[i] ) appendText(p, azArg[i], 0);
+ }
+ return 0;
+}
+
+/*
+** Generate an appropriate SELFTEST table in the main database.
+*/
+static void createSelftestTable(ShellState *p){
+ char *zErrMsg = 0;
+ sqlite3_exec(p->db,
+ "SAVEPOINT selftest_init;\n"
+ "CREATE TABLE IF NOT EXISTS selftest(\n"
+ " tno INTEGER PRIMARY KEY,\n" /* Test number */
+ " op TEXT,\n" /* Operator: memo run */
+ " cmd TEXT,\n" /* Command text */
+ " ans TEXT\n" /* Desired answer */
+ ");"
+ "CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n"
+ "INSERT INTO [_shell$self](rowid,op,cmd)\n"
+ " VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n"
+ " 'memo','Tests generated by --init');\n"
+ "INSERT INTO [_shell$self]\n"
+ " SELECT 'run',\n"
+ " 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql "
+ "FROM sqlite_master ORDER BY 2'',224))',\n"
+ " hex(sha3_query('SELECT type,name,tbl_name,sql "
+ "FROM sqlite_master ORDER BY 2',224));\n"
+ "INSERT INTO [_shell$self]\n"
+ " SELECT 'run',"
+ " 'SELECT hex(sha3_query(''SELECT * FROM \"' ||"
+ " printf('%w',name) || '\" NOT INDEXED'',224))',\n"
+ " hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n"
+ " FROM (\n"
+ " SELECT name FROM sqlite_master\n"
+ " WHERE type='table'\n"
+ " AND name<>'selftest'\n"
+ " AND coalesce(rootpage,0)>0\n"
+ " )\n"
+ " ORDER BY name;\n"
+ "INSERT INTO [_shell$self]\n"
+ " VALUES('run','PRAGMA integrity_check','ok');\n"
+ "INSERT INTO selftest(tno,op,cmd,ans)"
+ " SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n"
+ "DROP TABLE [_shell$self];"
+ ,0,0,&zErrMsg);
+ if( zErrMsg ){
+ utf8_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ }
+ sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
+}
+
+
+/*
+** Set the destination table field of the ShellState structure to
+** the name of the table given. Escape any quote characters in the
+** table name.
+*/
+static void set_table_name(ShellState *p, const char *zName){
+ int i, n;
+ char cQuote;
+ char *z;
+
+ if( p->zDestTable ){
+ free(p->zDestTable);
+ p->zDestTable = 0;
+ }
+ if( zName==0 ) return;
+ cQuote = quoteChar(zName);
+ n = strlen30(zName);
+ if( cQuote ) n += n+2;
+ z = p->zDestTable = malloc( n+1 );
+ if( z==0 ){
+ raw_printf(stderr,"Error: out of memory\n");
+ exit(1);
+ }
+ n = 0;
+ if( cQuote ) z[n++] = cQuote;
+ for(i=0; zName[i]; i++){
+ z[n++] = zName[i];
+ if( zName[i]==cQuote ) z[n++] = cQuote;
+ }
+ if( cQuote ) z[n++] = cQuote;
+ z[n] = 0;
+}
+
+
+/*
+** Execute a query statement that will generate SQL output. Print
+** the result columns, comma-separated, on a line and then add a
+** semicolon terminator to the end of that line.
+**
+** If the number of columns is 1 and that column contains text "--"
+** then write the semicolon on a separate line. That way, if a
+** "--" comment occurs at the end of the statement, the comment
+** won't consume the semicolon terminator.
+*/
+static int run_table_dump_query(
+ ShellState *p, /* Query context */
+ const char *zSelect, /* SELECT statement to extract content */
+ const char *zFirstRow /* Print before first row, if not NULL */
+){
+ sqlite3_stmt *pSelect;
+ int rc;
+ int nResult;
+ int i;
+ const char *z;
+ rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
+ if( rc!=SQLITE_OK || !pSelect ){
+ utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
+ sqlite3_errmsg(p->db));
+ if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
+ return rc;
+ }
+ rc = sqlite3_step(pSelect);
+ nResult = sqlite3_column_count(pSelect);
+ while( rc==SQLITE_ROW ){
+ if( zFirstRow ){
+ utf8_printf(p->out, "%s", zFirstRow);
+ zFirstRow = 0;
+ }
+ z = (const char*)sqlite3_column_text(pSelect, 0);
+ utf8_printf(p->out, "%s", z);
+ for(i=1; i<nResult; i++){
+ utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i));
+ }
+ if( z==0 ) z = "";
+ while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
+ if( z[0] ){
+ raw_printf(p->out, "\n;\n");
+ }else{
+ raw_printf(p->out, ";\n");
+ }
+ rc = sqlite3_step(pSelect);
+ }
+ rc = sqlite3_finalize(pSelect);
+ if( rc!=SQLITE_OK ){
+ utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
+ sqlite3_errmsg(p->db));
+ if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
+ }
+ return rc;
+}
+
+/*
+** Allocate space and save off current error string.
+*/
+static char *save_err_msg(
+ sqlite3 *db /* Database to query */
+){
+ int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
+ char *zErrMsg = sqlite3_malloc64(nErrMsg);
+ if( zErrMsg ){
+ memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
+ }
+ return zErrMsg;
+}
+
+#ifdef __linux__
+/*
+** Attempt to display I/O stats on Linux using /proc/PID/io
+*/
+static void displayLinuxIoStats(FILE *out){
+ FILE *in;
+ char z[200];
+ sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
+ in = fopen(z, "rb");
+ if( in==0 ) return;
+ while( fgets(z, sizeof(z), in)!=0 ){
+ static const struct {
+ const char *zPattern;
+ const char *zDesc;
+ } aTrans[] = {
+ { "rchar: ", "Bytes received by read():" },
+ { "wchar: ", "Bytes sent to write():" },
+ { "syscr: ", "Read() system calls:" },
+ { "syscw: ", "Write() system calls:" },
+ { "read_bytes: ", "Bytes read from storage:" },
+ { "write_bytes: ", "Bytes written to storage:" },
+ { "cancelled_write_bytes: ", "Cancelled write bytes:" },
+ };
+ int i;
+ for(i=0; i<ArraySize(aTrans); i++){
+ int n = (int)strlen(aTrans[i].zPattern);
+ if( strncmp(aTrans[i].zPattern, z, n)==0 ){
+ utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
+ break;
+ }
+ }
+ }
+ fclose(in);
+}
+#endif
+
+/*
+** Display a single line of status using 64-bit values.
+*/
+static void displayStatLine(
+ ShellState *p, /* The shell context */
+ char *zLabel, /* Label for this one line */
+ char *zFormat, /* Format for the result */
+ int iStatusCtrl, /* Which status to display */
+ int bReset /* True to reset the stats */
+){
+ sqlite3_int64 iCur = -1;
+ sqlite3_int64 iHiwtr = -1;
+ int i, nPercent;
+ char zLine[200];
+ sqlite3_status64(iStatusCtrl, &iCur, &iHiwtr, bReset);
+ for(i=0, nPercent=0; zFormat[i]; i++){
+ if( zFormat[i]=='%' ) nPercent++;
+ }
+ if( nPercent>1 ){
+ sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr);
+ }else{
+ sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
+ }
+ raw_printf(p->out, "%-36s %s\n", zLabel, zLine);
+}
+
+/*
+** Display memory stats.
+*/
+static int display_stats(
+ sqlite3 *db, /* Database to query */
+ ShellState *pArg, /* Pointer to ShellState */
+ int bReset /* True to reset the stats */
+){
+ int iCur;
+ int iHiwtr;
+
+ if( pArg && pArg->out ){
+ displayStatLine(pArg, "Memory Used:",
+ "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
+ displayStatLine(pArg, "Number of Outstanding Allocations:",
+ "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
+ if( pArg->shellFlgs & SHFLG_Pagecache ){
+ displayStatLine(pArg, "Number of Pcache Pages Used:",
+ "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
+ }
+ displayStatLine(pArg, "Number of Pcache Overflow Bytes:",
+ "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
+ displayStatLine(pArg, "Largest Allocation:",
+ "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
+ displayStatLine(pArg, "Largest Pcache Allocation:",
+ "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
+#ifdef YYTRACKMAXSTACKDEPTH
+ displayStatLine(pArg, "Deepest Parser Stack:",
+ "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
+#endif
+ }
+
+ if( pArg && pArg->out && db ){
+ if( pArg->shellFlgs & SHFLG_Lookaside ){
+ iHiwtr = iCur = -1;
+ sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
+ &iCur, &iHiwtr, bReset);
+ raw_printf(pArg->out,
+ "Lookaside Slots Used: %d (max %d)\n",
+ iCur, iHiwtr);
+ sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
+ &iCur, &iHiwtr, bReset);
+ raw_printf(pArg->out, "Successful lookaside attempts: %d\n",
+ iHiwtr);
+ sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
+ &iCur, &iHiwtr, bReset);
+ raw_printf(pArg->out, "Lookaside failures due to size: %d\n",
+ iHiwtr);
+ sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
+ &iCur, &iHiwtr, bReset);
+ raw_printf(pArg->out, "Lookaside failures due to OOM: %d\n",
+ iHiwtr);
+ }
+ iHiwtr = iCur = -1;
+ sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
+ raw_printf(pArg->out, "Pager Heap Usage: %d bytes\n",
+ iCur);
+ iHiwtr = iCur = -1;
+ sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
+ raw_printf(pArg->out, "Page cache hits: %d\n", iCur);
+ iHiwtr = iCur = -1;
+ sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
+ raw_printf(pArg->out, "Page cache misses: %d\n", iCur);
+ iHiwtr = iCur = -1;
+ sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
+ raw_printf(pArg->out, "Page cache writes: %d\n", iCur);
+ iHiwtr = iCur = -1;
+ sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
+ raw_printf(pArg->out, "Schema Heap Usage: %d bytes\n",
+ iCur);
+ iHiwtr = iCur = -1;
+ sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
+ raw_printf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n",
+ iCur);
+ }
+
+ if( pArg && pArg->out && db && pArg->pStmt ){
+ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
+ bReset);
+ raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur);
+ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
+ raw_printf(pArg->out, "Sort Operations: %d\n", iCur);
+ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
+ raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur);
+ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
+ raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
+ }
+
+#ifdef __linux__
+ displayLinuxIoStats(pArg->out);
+#endif
+
+ /* Do not remove this machine readable comment: extra-stats-output-here */
+
+ return 0;
+}
+
+/*
+** Display scan stats.
+*/
+static void display_scanstats(
+ sqlite3 *db, /* Database to query */
+ ShellState *pArg /* Pointer to ShellState */
+){
+#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
+ UNUSED_PARAMETER(db);
+ UNUSED_PARAMETER(pArg);
+#else
+ int i, k, n, mx;
+ raw_printf(pArg->out, "-------- scanstats --------\n");
+ mx = 0;
+ for(k=0; k<=mx; k++){
+ double rEstLoop = 1.0;
+ for(i=n=0; 1; i++){
+ sqlite3_stmt *p = pArg->pStmt;
+ sqlite3_int64 nLoop, nVisit;
+ double rEst;
+ int iSid;
+ const char *zExplain;
+ if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){
+ break;
+ }
+ sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid);
+ if( iSid>mx ) mx = iSid;
+ if( iSid!=k ) continue;
+ if( n==0 ){
+ rEstLoop = (double)nLoop;
+ if( k>0 ) raw_printf(pArg->out, "-------- subquery %d -------\n", k);
+ }
+ n++;
+ sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
+ sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst);
+ sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
+ utf8_printf(pArg->out, "Loop %2d: %s\n", n, zExplain);
+ rEstLoop *= rEst;
+ raw_printf(pArg->out,
+ " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
+ nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
+ );
+ }
+ }
+ raw_printf(pArg->out, "---------------------------\n");
+#endif
+}
+
+/*
+** Parameter azArray points to a zero-terminated array of strings. zStr
+** points to a single nul-terminated string. Return non-zero if zStr
+** is equal, according to strcmp(), to any of the strings in the array.
+** Otherwise, return zero.
+*/
+static int str_in_array(const char *zStr, const char **azArray){
+ int i;
+ for(i=0; azArray[i]; i++){
+ if( 0==strcmp(zStr, azArray[i]) ) return 1;
+ }
+ return 0;
+}
+
+/*
+** If compiled statement pSql appears to be an EXPLAIN statement, allocate
+** and populate the ShellState.aiIndent[] array with the number of
+** spaces each opcode should be indented before it is output.
+**
+** The indenting rules are:
+**
+** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
+** all opcodes that occur between the p2 jump destination and the opcode
+** itself by 2 spaces.
+**
+** * For each "Goto", if the jump destination is earlier in the program
+** and ends on one of:
+** Yield SeekGt SeekLt RowSetRead Rewind
+** or if the P1 parameter is one instead of zero,
+** then indent all opcodes between the earlier instruction
+** and "Goto" by 2 spaces.
+*/
+static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
+ const char *zSql; /* The text of the SQL statement */
+ const char *z; /* Used to check if this is an EXPLAIN */
+ int *abYield = 0; /* True if op is an OP_Yield */
+ int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
+ int iOp; /* Index of operation in p->aiIndent[] */
+
+ const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
+ "NextIfOpen", "PrevIfOpen", 0 };
+ const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
+ "Rewind", 0 };
+ const char *azGoto[] = { "Goto", 0 };
+
+ /* Try to figure out if this is really an EXPLAIN statement. If this
+ ** cannot be verified, return early. */
+ if( sqlite3_column_count(pSql)!=8 ){
+ p->cMode = p->mode;
+ return;
+ }
+ zSql = sqlite3_sql(pSql);
+ if( zSql==0 ) return;
+ for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
+ if( sqlite3_strnicmp(z, "explain", 7) ){
+ p->cMode = p->mode;
+ return;
+ }
+
+ for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
+ int i;
+ int iAddr = sqlite3_column_int(pSql, 0);
+ const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
+
+ /* Set p2 to the P2 field of the current opcode. Then, assuming that
+ ** p2 is an instruction address, set variable p2op to the index of that
+ ** instruction in the aiIndent[] array. p2 and p2op may be different if
+ ** the current instruction is part of a sub-program generated by an
+ ** SQL trigger or foreign key. */
+ int p2 = sqlite3_column_int(pSql, 3);
+ int p2op = (p2 + (iOp-iAddr));
+
+ /* Grow the p->aiIndent array as required */
+ if( iOp>=nAlloc ){
+ if( iOp==0 ){
+ /* Do further verfication that this is explain output. Abort if
+ ** it is not */
+ static const char *explainCols[] = {
+ "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
+ int jj;
+ for(jj=0; jj<ArraySize(explainCols); jj++){
+ if( strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
+ p->cMode = p->mode;
+ sqlite3_reset(pSql);
+ return;
+ }
+ }
+ }
+ nAlloc += 100;
+ p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
+ abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
+ }
+ abYield[iOp] = str_in_array(zOp, azYield);
+ p->aiIndent[iOp] = 0;
+ p->nIndent = iOp+1;
+
+ if( str_in_array(zOp, azNext) ){
+ for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
+ }
+ if( str_in_array(zOp, azGoto) && p2op<p->nIndent
+ && (abYield[p2op] || sqlite3_column_int(pSql, 2))
+ ){
+ for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
+ }
+ }
+
+ p->iIndent = 0;
+ sqlite3_free(abYield);
+ sqlite3_reset(pSql);
+}
+
+/*
+** Free the array allocated by explain_data_prepare().
+*/
+static void explain_data_delete(ShellState *p){
+ sqlite3_free(p->aiIndent);
+ p->aiIndent = 0;
+ p->nIndent = 0;
+ p->iIndent = 0;
+}
+
+/*
+** Disable and restore .wheretrace and .selecttrace settings.
+*/
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
+extern int sqlite3SelectTrace;
+static int savedSelectTrace;
+#endif
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
+extern int sqlite3WhereTrace;
+static int savedWhereTrace;
+#endif
+static void disable_debug_trace_modes(void){
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
+ savedSelectTrace = sqlite3SelectTrace;
+ sqlite3SelectTrace = 0;
+#endif
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
+ savedWhereTrace = sqlite3WhereTrace;
+ sqlite3WhereTrace = 0;
+#endif
+}
+static void restore_debug_trace_modes(void){
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
+ sqlite3SelectTrace = savedSelectTrace;
+#endif
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
+ sqlite3WhereTrace = savedWhereTrace;
+#endif
+}
+
+/*
+** Run a prepared statement
+*/
+static void exec_prepared_stmt(
+ ShellState *pArg, /* Pointer to ShellState */
+ sqlite3_stmt *pStmt, /* Statment to run */
+ int (*xCallback)(void*,int,char**,char**,int*) /* Callback function */
+){
+ int rc;
+
+ /* perform the first step. this will tell us if we
+ ** have a result set or not and how wide it is.
+ */
+ rc = sqlite3_step(pStmt);
+ /* if we have a result set... */
+ if( SQLITE_ROW == rc ){
+ /* if we have a callback... */
+ if( xCallback ){
+ /* allocate space for col name ptr, value ptr, and type */
+ int nCol = sqlite3_column_count(pStmt);
+ void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
+ if( !pData ){
+ rc = SQLITE_NOMEM;
+ }else{
+ char **azCols = (char **)pData; /* Names of result columns */
+ char **azVals = &azCols[nCol]; /* Results */
+ int *aiTypes = (int *)&azVals[nCol]; /* Result types */
+ int i, x;
+ assert(sizeof(int) <= sizeof(char *));
+ /* save off ptrs to column names */
+ for(i=0; i<nCol; i++){
+ azCols[i] = (char *)sqlite3_column_name(pStmt, i);
+ }
+ do{
+ /* extract the data and data types */
+ for(i=0; i<nCol; i++){
+ aiTypes[i] = x = sqlite3_column_type(pStmt, i);
+ if( x==SQLITE_BLOB && pArg && pArg->cMode==MODE_Insert ){
+ azVals[i] = "";
+ }else{
+ azVals[i] = (char*)sqlite3_column_text(pStmt, i);
+ }
+ if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
+ rc = SQLITE_NOMEM;
+ break; /* from for */
+ }
+ } /* end for */
+
+ /* if data and types extracted successfully... */
+ if( SQLITE_ROW == rc ){
+ /* call the supplied callback with the result row data */
+ if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
+ rc = SQLITE_ABORT;
+ }else{
+ rc = sqlite3_step(pStmt);
+ }
+ }
+ } while( SQLITE_ROW == rc );
+ sqlite3_free(pData);
+ }
+ }else{
+ do{
+ rc = sqlite3_step(pStmt);
+ } while( rc == SQLITE_ROW );
+ }
+ }
+}
+
+/*
+** Execute a statement or set of statements. Print
+** any result rows/columns depending on the current mode
+** set via the supplied callback.
+**
+** This is very similar to SQLite's built-in sqlite3_exec()
+** function except it takes a slightly different callback
+** and callback data argument.
+*/
+static int shell_exec(
+ sqlite3 *db, /* An open database */
+ const char *zSql, /* SQL to be evaluated */
+ int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */
+ /* (not the same as sqlite3_exec) */
+ ShellState *pArg, /* Pointer to ShellState */
+ char **pzErrMsg /* Error msg written here */
+){
+ sqlite3_stmt *pStmt = NULL; /* Statement to execute. */
+ int rc = SQLITE_OK; /* Return Code */
+ int rc2;
+ const char *zLeftover; /* Tail of unprocessed SQL */
+
+ if( pzErrMsg ){
+ *pzErrMsg = NULL;
+ }
+
+ while( zSql[0] && (SQLITE_OK == rc) ){
+ static const char *zStmtSql;
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
+ if( SQLITE_OK != rc ){
+ if( pzErrMsg ){
+ *pzErrMsg = save_err_msg(db);
+ }
+ }else{
+ if( !pStmt ){
+ /* this happens for a comment or white-space */
+ zSql = zLeftover;
+ while( IsSpace(zSql[0]) ) zSql++;
+ continue;
+ }
+ zStmtSql = sqlite3_sql(pStmt);
+ if( zStmtSql==0 ) zStmtSql = "";
+ while( IsSpace(zStmtSql[0]) ) zStmtSql++;
+
+ /* save off the prepared statment handle and reset row count */
+ if( pArg ){
+ pArg->pStmt = pStmt;
+ pArg->cnt = 0;
+ }
+
+ /* echo the sql statement if echo on */
+ if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){
+ utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
+ }
+
+ /* Show the EXPLAIN QUERY PLAN if .eqp is on */
+ if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){
+ sqlite3_stmt *pExplain;
+ char *zEQP;
+ disable_debug_trace_modes();
+ zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
+ rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
+ if( rc==SQLITE_OK ){
+ while( sqlite3_step(pExplain)==SQLITE_ROW ){
+ raw_printf(pArg->out,"--EQP-- %d,",sqlite3_column_int(pExplain, 0));
+ raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
+ raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
+ utf8_printf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
+ }
+ }
+ sqlite3_finalize(pExplain);
+ sqlite3_free(zEQP);
+ if( pArg->autoEQP>=2 ){
+ /* Also do an EXPLAIN for ".eqp full" mode */
+ zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
+ rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
+ if( rc==SQLITE_OK ){
+ pArg->cMode = MODE_Explain;
+ explain_data_prepare(pArg, pExplain);
+ exec_prepared_stmt(pArg, pExplain, xCallback);
+ explain_data_delete(pArg);
+ }
+ sqlite3_finalize(pExplain);
+ sqlite3_free(zEQP);
+ }
+ restore_debug_trace_modes();
+ }
+
+ if( pArg ){
+ pArg->cMode = pArg->mode;
+ if( pArg->autoExplain
+ && sqlite3_column_count(pStmt)==8
+ && sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0
+ ){
+ pArg->cMode = MODE_Explain;
+ }
+
+ /* If the shell is currently in ".explain" mode, gather the extra
+ ** data required to add indents to the output.*/
+ if( pArg->cMode==MODE_Explain ){
+ explain_data_prepare(pArg, pStmt);
+ }
+ }
+
+ exec_prepared_stmt(pArg, pStmt, xCallback);
+ explain_data_delete(pArg);
+
+ /* print usage stats if stats on */
+ if( pArg && pArg->statsOn ){
+ display_stats(db, pArg, 0);
+ }
+
+ /* print loop-counters if required */
+ if( pArg && pArg->scanstatsOn ){
+ display_scanstats(db, pArg);
+ }
+
+ /* Finalize the statement just executed. If this fails, save a
+ ** copy of the error message. Otherwise, set zSql to point to the
+ ** next statement to execute. */
+ rc2 = sqlite3_finalize(pStmt);
+ if( rc!=SQLITE_NOMEM ) rc = rc2;
+ if( rc==SQLITE_OK ){
+ zSql = zLeftover;
+ while( IsSpace(zSql[0]) ) zSql++;
+ }else if( pzErrMsg ){
+ *pzErrMsg = save_err_msg(db);
+ }
+
+ /* clear saved stmt handle */
+ if( pArg ){
+ pArg->pStmt = NULL;
+ }
+ }
+ } /* end while */
+
+ return rc;
+}
+
+/*
+** Release memory previously allocated by tableColumnList().
+*/
+static void freeColumnList(char **azCol){
+ int i;
+ for(i=1; azCol[i]; i++){
+ sqlite3_free(azCol[i]);
+ }
+ /* azCol[0] is a static string */
+ sqlite3_free(azCol);
+}
+
+/*
+** Return a list of pointers to strings which are the names of all
+** columns in table zTab. The memory to hold the names is dynamically
+** allocated and must be released by the caller using a subsequent call
+** to freeColumnList().
+**
+** The azCol[0] entry is usually NULL. However, if zTab contains a rowid
+** value that needs to be preserved, then azCol[0] is filled in with the
+** name of the rowid column.
+**
+** The first regular column in the table is azCol[1]. The list is terminated
+** by an entry with azCol[i]==0.
+*/
+static char **tableColumnList(ShellState *p, const char *zTab){
+ char **azCol = 0;
+ sqlite3_stmt *pStmt;
+ char *zSql;
+ int nCol = 0;
+ int nAlloc = 0;
+ int nPK = 0; /* Number of PRIMARY KEY columns seen */
+ int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */
+ int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid);
+ int rc;
+
+ zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab);
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ) return 0;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ if( nCol>=nAlloc-2 ){
+ nAlloc = nAlloc*2 + nCol + 10;
+ azCol = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0]));
+ if( azCol==0 ){
+ raw_printf(stderr, "Error: out of memory\n");
+ exit(1);
+ }
+ }
+ azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
+ if( sqlite3_column_int(pStmt, 5) ){
+ nPK++;
+ if( nPK==1
+ && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2),
+ "INTEGER")==0
+ ){
+ isIPK = 1;
+ }else{
+ isIPK = 0;
+ }
+ }
+ }
+ sqlite3_finalize(pStmt);
+ if( azCol==0 ) return 0;
+ azCol[0] = 0;
+ azCol[nCol+1] = 0;
+
+ /* The decision of whether or not a rowid really needs to be preserved
+ ** is tricky. We never need to preserve a rowid for a WITHOUT ROWID table
+ ** or a table with an INTEGER PRIMARY KEY. We are unable to preserve
+ ** rowids on tables where the rowid is inaccessible because there are other
+ ** columns in the table named "rowid", "_rowid_", and "oid".
+ */
+ if( preserveRowid && isIPK ){
+ /* If a single PRIMARY KEY column with type INTEGER was seen, then it
+ ** might be an alise for the ROWID. But it might also be a WITHOUT ROWID
+ ** table or a INTEGER PRIMARY KEY DESC column, neither of which are
+ ** ROWID aliases. To distinguish these cases, check to see if
+ ** there is a "pk" entry in "PRAGMA index_list". There will be
+ ** no "pk" index if the PRIMARY KEY really is an alias for the ROWID.
+ */
+ zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)"
+ " WHERE origin='pk'", zTab);
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ){
+ freeColumnList(azCol);
+ return 0;
+ }
+ rc = sqlite3_step(pStmt);
+ sqlite3_finalize(pStmt);
+ preserveRowid = rc==SQLITE_ROW;
+ }
+ if( preserveRowid ){
+ /* Only preserve the rowid if we can find a name to use for the
+ ** rowid */
+ static char *azRowid[] = { "rowid", "_rowid_", "oid" };
+ int i, j;
+ for(j=0; j<3; j++){
+ for(i=1; i<=nCol; i++){
+ if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break;
+ }
+ if( i>nCol ){
+ /* At this point, we know that azRowid[j] is not the name of any
+ ** ordinary column in the table. Verify that azRowid[j] is a valid
+ ** name for the rowid before adding it to azCol[0]. WITHOUT ROWID
+ ** tables will fail this last check */
+ rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
+ if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
+ break;
+ }
+ }
+ }
+ return azCol;
+}
+
+/*
+** Toggle the reverse_unordered_selects setting.
+*/
+static void toggleSelectOrder(sqlite3 *db){
+ sqlite3_stmt *pStmt = 0;
+ int iSetting = 0;
+ char zStmt[100];
+ sqlite3_prepare_v2(db, "PRAGMA reverse_unordered_selects", -1, &pStmt, 0);
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ iSetting = sqlite3_column_int(pStmt, 0);
+ }
+ sqlite3_finalize(pStmt);
+ sqlite3_snprintf(sizeof(zStmt), zStmt,
+ "PRAGMA reverse_unordered_selects(%d)", !iSetting);
+ sqlite3_exec(db, zStmt, 0, 0, 0);
+}
+
+/*
+** This is a different callback routine used for dumping the database.
+** Each row received by this callback consists of a table name,
+** the table type ("index" or "table") and SQL to create the table.
+** This routine should print text sufficient to recreate the table.
+*/
+static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
+ int rc;
+ const char *zTable;
+ const char *zType;
+ const char *zSql;
+ ShellState *p = (ShellState *)pArg;
+
+ UNUSED_PARAMETER(azNotUsed);
+ if( nArg!=3 || azArg==0 ) return 0;
+ zTable = azArg[0];
+ zType = azArg[1];
+ zSql = azArg[2];
+
+ if( strcmp(zTable, "sqlite_sequence")==0 ){
+ raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
+ }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
+ raw_printf(p->out, "ANALYZE sqlite_master;\n");
+ }else if( strncmp(zTable, "sqlite_", 7)==0 ){
+ return 0;
+ }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
+ char *zIns;
+ if( !p->writableSchema ){
+ raw_printf(p->out, "PRAGMA writable_schema=ON;\n");
+ p->writableSchema = 1;
+ }
+ zIns = sqlite3_mprintf(
+ "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
+ "VALUES('table','%q','%q',0,'%q');",
+ zTable, zTable, zSql);
+ utf8_printf(p->out, "%s\n", zIns);
+ sqlite3_free(zIns);
+ return 0;
+ }else{
+ printSchemaLine(p->out, zSql, ";\n");
+ }
+
+ if( strcmp(zType, "table")==0 ){
+ ShellText sSelect;
+ ShellText sTable;
+ char **azCol;
+ int i;
+ char *savedDestTable;
+ int savedMode;
+
+ azCol = tableColumnList(p, zTable);
+ if( azCol==0 ){
+ p->nErr++;
+ return 0;
+ }
+
+ /* Always quote the table name, even if it appears to be pure ascii,
+ ** in case it is a keyword. Ex: INSERT INTO "table" ... */
+ initText(&sTable);
+ appendText(&sTable, zTable, quoteChar(zTable));
+ /* If preserving the rowid, add a column list after the table name.
+ ** In other words: "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
+ ** instead of the usual "INSERT INTO tab VALUES(...)".
+ */
+ if( azCol[0] ){
+ appendText(&sTable, "(", 0);
+ appendText(&sTable, azCol[0], 0);
+ for(i=1; azCol[i]; i++){
+ appendText(&sTable, ",", 0);
+ appendText(&sTable, azCol[i], quoteChar(azCol[i]));
+ }
+ appendText(&sTable, ")", 0);
+ }
+
+ /* Build an appropriate SELECT statement */
+ initText(&sSelect);
+ appendText(&sSelect, "SELECT ", 0);
+ if( azCol[0] ){
+ appendText(&sSelect, azCol[0], 0);
+ appendText(&sSelect, ",", 0);
+ }
+ for(i=1; azCol[i]; i++){
+ appendText(&sSelect, azCol[i], quoteChar(azCol[i]));
+ if( azCol[i+1] ){
+ appendText(&sSelect, ",", 0);
+ }
+ }
+ freeColumnList(azCol);
+ appendText(&sSelect, " FROM ", 0);
+ appendText(&sSelect, zTable, quoteChar(zTable));
+
+ savedDestTable = p->zDestTable;
+ savedMode = p->mode;
+ p->zDestTable = sTable.z;
+ p->mode = p->cMode = MODE_Insert;
+ rc = shell_exec(p->db, sSelect.z, shell_callback, p, 0);
+ if( (rc&0xff)==SQLITE_CORRUPT ){
+ raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
+ toggleSelectOrder(p->db);
+ shell_exec(p->db, sSelect.z, shell_callback, p, 0);
+ toggleSelectOrder(p->db);
+ }
+ p->zDestTable = savedDestTable;
+ p->mode = savedMode;
+ freeText(&sTable);
+ freeText(&sSelect);
+ if( rc ) p->nErr++;
+ }
+ return 0;
+}
+
+/*
+** Run zQuery. Use dump_callback() as the callback routine so that
+** the contents of the query are output as SQL statements.
+**
+** If we get a SQLITE_CORRUPT error, rerun the query after appending
+** "ORDER BY rowid DESC" to the end.
+*/
+static int run_schema_dump_query(
+ ShellState *p,
+ const char *zQuery
+){
+ int rc;
+ char *zErr = 0;
+ rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
+ if( rc==SQLITE_CORRUPT ){
+ char *zQ2;
+ int len = strlen30(zQuery);
+ raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
+ if( zErr ){
+ utf8_printf(p->out, "/****** %s ******/\n", zErr);
+ sqlite3_free(zErr);
+ zErr = 0;
+ }
+ zQ2 = malloc( len+100 );
+ if( zQ2==0 ) return rc;
+ sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
+ rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
+ if( rc ){
+ utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr);
+ }else{
+ rc = SQLITE_CORRUPT;
+ }
+ sqlite3_free(zErr);
+ free(zQ2);
+ }
+ return rc;
+}
+
+/*
+** Text of a help message
+*/
+static char zHelp[] =
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ ".auth ON|OFF Show authorizer callbacks\n"
+#endif
+ ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
+ ".bail on|off Stop after hitting an error. Default OFF\n"
+ ".binary on|off Turn binary output on or off. Default OFF\n"
+ ".cd DIRECTORY Change the working directory to DIRECTORY\n"
+ ".changes on|off Show number of rows changed by SQL\n"
+ ".check GLOB Fail if output since .testcase does not match\n"
+ ".clone NEWDB Clone data into NEWDB from the existing database\n"
+ ".databases List names and files of attached databases\n"
+ ".dbinfo ?DB? Show status information about the database\n"
+ ".dump ?TABLE? ... Dump the database in an SQL text format\n"
+ " If TABLE specified, only dump tables matching\n"
+ " LIKE pattern TABLE.\n"
+ ".echo on|off Turn command echo on or off\n"
+ ".eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN\n"
+ ".exit Exit this program\n"
+/* Because explain mode comes on automatically now, the ".explain" mode
+** is removed from the help screen. It is still supported for legacy, however */
+/*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"*/
+ ".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n"
+ ".headers on|off Turn display of headers on or off\n"
+ ".help Show this message\n"
+ ".import FILE TABLE Import data from FILE into TABLE\n"
+#ifndef SQLITE_OMIT_TEST_CONTROL
+ ".imposter INDEX TABLE Create imposter table TABLE on index INDEX\n"
+#endif
+ ".indexes ?TABLE? Show names of all indexes\n"
+ " If TABLE specified, only show indexes for tables\n"
+ " matching LIKE pattern TABLE.\n"
+#ifdef SQLITE_ENABLE_IOTRACE
+ ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
+#endif
+ ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT\n"
+ ".lint OPTIONS Report potential schema issues. Options:\n"
+ " fkey-indexes Find missing foreign key indexes\n"
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ ".load FILE ?ENTRY? Load an extension library\n"
+#endif
+ ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n"
+ ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
+ " ascii Columns/rows delimited by 0x1F and 0x1E\n"
+ " csv Comma-separated values\n"
+ " column Left-aligned columns. (See .width)\n"
+ " html HTML <table> code\n"
+ " insert SQL insert statements for TABLE\n"
+ " line One value per line\n"
+ " list Values delimited by \"|\"\n"
+ " quote Escape answers as for SQL\n"
+ " tabs Tab-separated values\n"
+ " tcl TCL list elements\n"
+ ".nullvalue STRING Use STRING in place of NULL values\n"
+ ".once FILENAME Output for the next SQL command only to FILENAME\n"
+ ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n"
+ " The --new option starts with an empty file\n"
+ ".output ?FILENAME? Send output to FILENAME or stdout\n"
+ ".print STRING... Print literal STRING\n"
+ ".prompt MAIN CONTINUE Replace the standard prompts\n"
+ ".quit Exit this program\n"
+ ".read FILENAME Execute SQL in FILENAME\n"
+ ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
+ ".save FILE Write in-memory database into FILE\n"
+ ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n"
+ ".schema ?PATTERN? Show the CREATE statements matching PATTERN\n"
+ " Add --indent for pretty-printing\n"
+ ".selftest ?--init? Run tests defined in the SELFTEST table\n"
+ ".separator COL ?ROW? Change the column separator and optionally the row\n"
+ " separator for both the output mode and .import\n"
+#if defined(SQLITE_ENABLE_SESSION)
+ ".session CMD ... Create or control sessions\n"
+#endif
+ ".sha3sum ?OPTIONS...? Compute a SHA3 hash of database content\n"
+ ".shell CMD ARGS... Run CMD ARGS... in a system shell\n"
+ ".show Show the current values for various settings\n"
+ ".stats ?on|off? Show stats or turn stats on or off\n"
+ ".system CMD ARGS... Run CMD ARGS... in a system shell\n"
+ ".tables ?TABLE? List names of tables\n"
+ " If TABLE specified, only list tables matching\n"
+ " LIKE pattern TABLE.\n"
+ ".testcase NAME Begin redirecting output to 'testcase-out.txt'\n"
+ ".timeout MS Try opening locked tables for MS milliseconds\n"
+ ".timer on|off Turn SQL timer on or off\n"
+ ".trace FILE|off Output each SQL statement as it is run\n"
+ ".vfsinfo ?AUX? Information about the top-level VFS\n"
+ ".vfslist List all available VFSes\n"
+ ".vfsname ?AUX? Print the name of the VFS stack\n"
+ ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
+ " Negative values right-justify\n"
+;
+
+#if defined(SQLITE_ENABLE_SESSION)
+/*
+** Print help information for the ".sessions" command
+*/
+void session_help(ShellState *p){
+ raw_printf(p->out,
+ ".session ?NAME? SUBCOMMAND ?ARGS...?\n"
+ "If ?NAME? is omitted, the first defined session is used.\n"
+ "Subcommands:\n"
+ " attach TABLE Attach TABLE\n"
+ " changeset FILE Write a changeset into FILE\n"
+ " close Close one session\n"
+ " enable ?BOOLEAN? Set or query the enable bit\n"
+ " filter GLOB... Reject tables matching GLOBs\n"
+ " indirect ?BOOLEAN? Mark or query the indirect status\n"
+ " isempty Query whether the session is empty\n"
+ " list List currently open session names\n"
+ " open DB NAME Open a new session on DB\n"
+ " patchset FILE Write a patchset into FILE\n"
+ );
+}
+#endif
+
+
+/* Forward reference */
+static int process_input(ShellState *p, FILE *in);
+
+/*
+** Read the content of file zName into memory obtained from sqlite3_malloc64()
+** and return a pointer to the buffer. The caller is responsible for freeing
+** the memory.
+**
+** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
+** read.
+**
+** For convenience, a nul-terminator byte is always appended to the data read
+** from the file before the buffer is returned. This byte is not included in
+** the final value of (*pnByte), if applicable.
+**
+** NULL is returned if any error is encountered. The final value of *pnByte
+** is undefined in this case.
+*/
+static char *readFile(const char *zName, int *pnByte){
+ FILE *in = fopen(zName, "rb");
+ long nIn;
+ size_t nRead;
+ char *pBuf;
+ if( in==0 ) return 0;
+ fseek(in, 0, SEEK_END);
+ nIn = ftell(in);
+ rewind(in);
+ pBuf = sqlite3_malloc64( nIn+1 );
+ if( pBuf==0 ) return 0;
+ nRead = fread(pBuf, nIn, 1, in);
+ fclose(in);
+ if( nRead!=1 ){
+ sqlite3_free(pBuf);
+ return 0;
+ }
+ pBuf[nIn] = 0;
+ if( pnByte ) *pnByte = nIn;
+ return pBuf;
+}
+
+#if defined(SQLITE_ENABLE_SESSION)
+/*
+** Close a single OpenSession object and release all of its associated
+** resources.
+*/
+static void session_close(OpenSession *pSession){
+ int i;
+ sqlite3session_delete(pSession->p);
+ sqlite3_free(pSession->zName);
+ for(i=0; i<pSession->nFilter; i++){
+ sqlite3_free(pSession->azFilter[i]);
+ }
+ sqlite3_free(pSession->azFilter);
+ memset(pSession, 0, sizeof(OpenSession));
+}
+#endif
+
+/*
+** Close all OpenSession objects and release all associated resources.
+*/
+#if defined(SQLITE_ENABLE_SESSION)
+static void session_close_all(ShellState *p){
+ int i;
+ for(i=0; i<p->nSession; i++){
+ session_close(&p->aSession[i]);
+ }
+ p->nSession = 0;
+}
+#else
+# define session_close_all(X)
+#endif
+
+/*
+** Implementation of the xFilter function for an open session. Omit
+** any tables named by ".session filter" but let all other table through.
+*/
+#if defined(SQLITE_ENABLE_SESSION)
+static int session_filter(void *pCtx, const char *zTab){
+ OpenSession *pSession = (OpenSession*)pCtx;
+ int i;
+ for(i=0; i<pSession->nFilter; i++){
+ if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
+ }
+ return 1;
+}
+#endif
+
+/*
+** Make sure the database is open. If it is not, then open it. If
+** the database fails to open, print an error message and exit.
+*/
+static void open_db(ShellState *p, int keepAlive){
+ if( p->db==0 ){
+ sqlite3_initialize();
+ sqlite3_open(p->zDbFilename, &p->db);
+ globalDb = p->db;
+ if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
+ utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
+ p->zDbFilename, sqlite3_errmsg(p->db));
+ if( keepAlive ) return;
+ exit(1);
+ }
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ sqlite3_enable_load_extension(p->db, 1);
+#endif
+ sqlite3_fileio_init(p->db, 0, 0);
+ sqlite3_shathree_init(p->db, 0, 0);
+ sqlite3_completion_init(p->db, 0, 0);
+ sqlite3_create_function(p->db, "shell_add_schema", 2, SQLITE_UTF8, 0,
+ shellAddSchemaName, 0, 0);
+ }
+}
+
+#if HAVE_READLINE || HAVE_EDITLINE
+/*
+** Readline completion callbacks
+*/
+static char *readline_completion_generator(const char *text, int state){
+ static sqlite3_stmt *pStmt = 0;
+ char *zRet;
+ if( state==0 ){
+ char *zSql;
+ sqlite3_finalize(pStmt);
+ zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
+ " FROM completion(%Q) ORDER BY 1", text);
+ sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ }
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ zRet = strdup((const char*)sqlite3_column_text(pStmt, 0));
+ }else{
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ zRet = 0;
+ }
+ return zRet;
+}
+static char **readline_completion(const char *zText, int iStart, int iEnd){
+ rl_attempted_completion_over = 1;
+ return rl_completion_matches(zText, readline_completion_generator);
+}
+
+#elif HAVE_LINENOISE
+/*
+** Linenoise completion callback
+*/
+static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
+ int nLine = (int)strlen(zLine);
+ int i, iStart;
+ sqlite3_stmt *pStmt = 0;
+ char *zSql;
+ char zBuf[1000];
+
+ if( nLine>sizeof(zBuf)-30 ) return;
+ if( zLine[0]=='.' ) return;
+ for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
+ if( i==nLine-1 ) return;
+ iStart = i+1;
+ memcpy(zBuf, zLine, iStart);
+ zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
+ " FROM completion(%Q,%Q) ORDER BY 1",
+ &zLine[iStart], zLine);
+ sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0);
+ int nCompletion = sqlite3_column_bytes(pStmt, 0);
+ if( iStart+nCompletion < sizeof(zBuf)-1 ){
+ memcpy(zBuf+iStart, zCompletion, nCompletion+1);
+ linenoiseAddCompletion(lc, zBuf);
+ }
+ }
+ sqlite3_finalize(pStmt);
+}
+#endif
+
+/*
+** Do C-language style dequoting.
+**
+** \a -> alarm
+** \b -> backspace
+** \t -> tab
+** \n -> newline
+** \v -> vertical tab
+** \f -> form feed
+** \r -> carriage return
+** \s -> space
+** \" -> "
+** \' -> '
+** \\ -> backslash
+** \NNN -> ascii character NNN in octal
+*/
+static void resolve_backslashes(char *z){
+ int i, j;
+ char c;
+ while( *z && *z!='\\' ) z++;
+ for(i=j=0; (c = z[i])!=0; i++, j++){
+ if( c=='\\' && z[i+1]!=0 ){
+ c = z[++i];
+ if( c=='a' ){
+ c = '\a';
+ }else if( c=='b' ){
+ c = '\b';
+ }else if( c=='t' ){
+ c = '\t';
+ }else if( c=='n' ){
+ c = '\n';
+ }else if( c=='v' ){
+ c = '\v';
+ }else if( c=='f' ){
+ c = '\f';
+ }else if( c=='r' ){
+ c = '\r';
+ }else if( c=='"' ){
+ c = '"';
+ }else if( c=='\'' ){
+ c = '\'';
+ }else if( c=='\\' ){
+ c = '\\';
+ }else if( c>='0' && c<='7' ){
+ c -= '0';
+ if( z[i+1]>='0' && z[i+1]<='7' ){
+ i++;
+ c = (c<<3) + z[i] - '0';
+ if( z[i+1]>='0' && z[i+1]<='7' ){
+ i++;
+ c = (c<<3) + z[i] - '0';
+ }
+ }
+ }
+ }
+ z[j] = c;
+ }
+ if( j<i ) z[j] = 0;
+}
+
+/*
+** Return the value of a hexadecimal digit. Return -1 if the input
+** is not a hex digit.
+*/
+static int hexDigitValue(char c){
+ if( c>='0' && c<='9' ) return c - '0';
+ if( c>='a' && c<='f' ) return c - 'a' + 10;
+ if( c>='A' && c<='F' ) return c - 'A' + 10;
+ return -1;
+}
+
+/*
+** Interpret zArg as an integer value, possibly with suffixes.
+*/
+static sqlite3_int64 integerValue(const char *zArg){
+ sqlite3_int64 v = 0;
+ static const struct { char *zSuffix; int iMult; } aMult[] = {
+ { "KiB", 1024 },
+ { "MiB", 1024*1024 },
+ { "GiB", 1024*1024*1024 },
+ { "KB", 1000 },
+ { "MB", 1000000 },
+ { "GB", 1000000000 },
+ { "K", 1000 },
+ { "M", 1000000 },
+ { "G", 1000000000 },
+ };
+ int i;
+ int isNeg = 0;
+ if( zArg[0]=='-' ){
+ isNeg = 1;
+ zArg++;
+ }else if( zArg[0]=='+' ){
+ zArg++;
+ }
+ if( zArg[0]=='0' && zArg[1]=='x' ){
+ int x;
+ zArg += 2;
+ while( (x = hexDigitValue(zArg[0]))>=0 ){
+ v = (v<<4) + x;
+ zArg++;
+ }
+ }else{
+ while( IsDigit(zArg[0]) ){
+ v = v*10 + zArg[0] - '0';
+ zArg++;
+ }
+ }
+ for(i=0; i<ArraySize(aMult); i++){
+ if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
+ v *= aMult[i].iMult;
+ break;
+ }
+ }
+ return isNeg? -v : v;
+}
+
+/*
+** Interpret zArg as either an integer or a boolean value. Return 1 or 0
+** for TRUE and FALSE. Return the integer value if appropriate.
+*/
+static int booleanValue(const char *zArg){
+ int i;
+ if( zArg[0]=='0' && zArg[1]=='x' ){
+ for(i=2; hexDigitValue(zArg[i])>=0; i++){}
+ }else{
+ for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
+ }
+ if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
+ if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
+ return 1;
+ }
+ if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
+ return 0;
+ }
+ utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
+ zArg);
+ return 0;
+}
+
+/*
+** Set or clear a shell flag according to a boolean value.
+*/
+static void setOrClearFlag(ShellState *p, unsigned mFlag, const char *zArg){
+ if( booleanValue(zArg) ){
+ ShellSetFlag(p, mFlag);
+ }else{
+ ShellClearFlag(p, mFlag);
+ }
+}
+
+/*
+** Close an output file, assuming it is not stderr or stdout
+*/
+static void output_file_close(FILE *f){
+ if( f && f!=stdout && f!=stderr ) fclose(f);
+}
+
+/*
+** Try to open an output file. The names "stdout" and "stderr" are
+** recognized and do the right thing. NULL is returned if the output
+** filename is "off".
+*/
+static FILE *output_file_open(const char *zFile){
+ FILE *f;
+ if( strcmp(zFile,"stdout")==0 ){
+ f = stdout;
+ }else if( strcmp(zFile, "stderr")==0 ){
+ f = stderr;
+ }else if( strcmp(zFile, "off")==0 ){
+ f = 0;
+ }else{
+ f = fopen(zFile, "wb");
+ if( f==0 ){
+ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
+ }
+ }
+ return f;
+}
+
+#if !defined(SQLITE_UNTESTABLE)
+#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
+/*
+** A routine for handling output from sqlite3_trace().
+*/
+static int sql_trace_callback(
+ unsigned mType,
+ void *pArg,
+ void *pP,
+ void *pX
+){
+ FILE *f = (FILE*)pArg;
+ UNUSED_PARAMETER(mType);
+ UNUSED_PARAMETER(pP);
+ if( f ){
+ const char *z = (const char*)pX;
+ int i = (int)strlen(z);
+ while( i>0 && z[i-1]==';' ){ i--; }
+ utf8_printf(f, "%.*s;\n", i, z);
+ }
+ return 0;
+}
+#endif
+#endif
+
+/*
+** A no-op routine that runs with the ".breakpoint" doc-command. This is
+** a useful spot to set a debugger breakpoint.
+*/
+static void test_breakpoint(void){
+ static int nCall = 0;
+ nCall++;
+}
+
+/*
+** An object used to read a CSV and other files for import.
+*/
+typedef struct ImportCtx ImportCtx;
+struct ImportCtx {
+ const char *zFile; /* Name of the input file */
+ FILE *in; /* Read the CSV text from this input stream */
+ char *z; /* Accumulated text for a field */
+ int n; /* Number of bytes in z */
+ int nAlloc; /* Space allocated for z[] */
+ int nLine; /* Current line number */
+ int bNotFirst; /* True if one or more bytes already read */
+ int cTerm; /* Character that terminated the most recent field */
+ int cColSep; /* The column separator character. (Usually ",") */
+ int cRowSep; /* The row separator character. (Usually "\n") */
+};
+
+/* Append a single byte to z[] */
+static void import_append_char(ImportCtx *p, int c){
+ if( p->n+1>=p->nAlloc ){
+ p->nAlloc += p->nAlloc + 100;
+ p->z = sqlite3_realloc64(p->z, p->nAlloc);
+ if( p->z==0 ){
+ raw_printf(stderr, "out of memory\n");
+ exit(1);
+ }
+ }
+ p->z[p->n++] = (char)c;
+}
+
+/* Read a single field of CSV text. Compatible with rfc4180 and extended
+** with the option of having a separator other than ",".
+**
+** + Input comes from p->in.
+** + Store results in p->z of length p->n. Space to hold p->z comes
+** from sqlite3_malloc64().
+** + Use p->cSep as the column separator. The default is ",".
+** + Use p->rSep as the row separator. The default is "\n".
+** + Keep track of the line number in p->nLine.
+** + Store the character that terminates the field in p->cTerm. Store
+** EOF on end-of-file.
+** + Report syntax errors on stderr
+*/
+static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
+ int c;
+ int cSep = p->cColSep;
+ int rSep = p->cRowSep;
+ p->n = 0;
+ c = fgetc(p->in);
+ if( c==EOF || seenInterrupt ){
+ p->cTerm = EOF;
+ return 0;
+ }
+ if( c=='"' ){
+ int pc, ppc;
+ int startLine = p->nLine;
+ int cQuote = c;
+ pc = ppc = 0;
+ while( 1 ){
+ c = fgetc(p->in);
+ if( c==rSep ) p->nLine++;
+ if( c==cQuote ){
+ if( pc==cQuote ){
+ pc = 0;
+ continue;
+ }
+ }
+ if( (c==cSep && pc==cQuote)
+ || (c==rSep && pc==cQuote)
+ || (c==rSep && pc=='\r' && ppc==cQuote)
+ || (c==EOF && pc==cQuote)
+ ){
+ do{ p->n--; }while( p->z[p->n]!=cQuote );
+ p->cTerm = c;
+ break;
+ }
+ if( pc==cQuote && c!='\r' ){
+ utf8_printf(stderr, "%s:%d: unescaped %c character\n",
+ p->zFile, p->nLine, cQuote);
+ }
+ if( c==EOF ){
+ utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n",
+ p->zFile, startLine, cQuote);
+ p->cTerm = c;
+ break;
+ }
+ import_append_char(p, c);
+ ppc = pc;
+ pc = c;
+ }
+ }else{
+ /* If this is the first field being parsed and it begins with the
+ ** UTF-8 BOM (0xEF BB BF) then skip the BOM */
+ if( (c&0xff)==0xef && p->bNotFirst==0 ){
+ import_append_char(p, c);
+ c = fgetc(p->in);
+ if( (c&0xff)==0xbb ){
+ import_append_char(p, c);
+ c = fgetc(p->in);
+ if( (c&0xff)==0xbf ){
+ p->bNotFirst = 1;
+ p->n = 0;
+ return csv_read_one_field(p);
+ }
+ }
+ }
+ while( c!=EOF && c!=cSep && c!=rSep ){
+ import_append_char(p, c);
+ c = fgetc(p->in);
+ }
+ if( c==rSep ){
+ p->nLine++;
+ if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
+ }
+ p->cTerm = c;
+ }
+ if( p->z ) p->z[p->n] = 0;
+ p->bNotFirst = 1;
+ return p->z;
+}
+
+/* Read a single field of ASCII delimited text.
+**
+** + Input comes from p->in.
+** + Store results in p->z of length p->n. Space to hold p->z comes
+** from sqlite3_malloc64().
+** + Use p->cSep as the column separator. The default is "\x1F".
+** + Use p->rSep as the row separator. The default is "\x1E".
+** + Keep track of the row number in p->nLine.
+** + Store the character that terminates the field in p->cTerm. Store
+** EOF on end-of-file.
+** + Report syntax errors on stderr
+*/
+static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
+ int c;
+ int cSep = p->cColSep;
+ int rSep = p->cRowSep;
+ p->n = 0;
+ c = fgetc(p->in);
+ if( c==EOF || seenInterrupt ){
+ p->cTerm = EOF;
+ return 0;
+ }
+ while( c!=EOF && c!=cSep && c!=rSep ){
+ import_append_char(p, c);
+ c = fgetc(p->in);
+ }
+ if( c==rSep ){
+ p->nLine++;
+ }
+ p->cTerm = c;
+ if( p->z ) p->z[p->n] = 0;
+ return p->z;
+}
+
+/*
+** Try to transfer data for table zTable. If an error is seen while
+** moving forward, try to go backwards. The backwards movement won't
+** work for WITHOUT ROWID tables.
+*/
+static void tryToCloneData(
+ ShellState *p,
+ sqlite3 *newDb,
+ const char *zTable
+){
+ sqlite3_stmt *pQuery = 0;
+ sqlite3_stmt *pInsert = 0;
+ char *zQuery = 0;
+ char *zInsert = 0;
+ int rc;
+ int i, j, n;
+ int nTable = (int)strlen(zTable);
+ int k = 0;
+ int cnt = 0;
+ const int spinRate = 10000;
+
+ zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
+ rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
+ if( rc ){
+ utf8_printf(stderr, "Error %d: %s on [%s]\n",
+ sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
+ zQuery);
+ goto end_data_xfer;
+ }
+ n = sqlite3_column_count(pQuery);
+ zInsert = sqlite3_malloc64(200 + nTable + n*3);
+ if( zInsert==0 ){
+ raw_printf(stderr, "out of memory\n");
+ goto end_data_xfer;
+ }
+ sqlite3_snprintf(200+nTable,zInsert,
+ "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
+ i = (int)strlen(zInsert);
+ for(j=1; j<n; j++){
+ memcpy(zInsert+i, ",?", 2);
+ i += 2;
+ }
+ memcpy(zInsert+i, ");", 3);
+ rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
+ if( rc ){
+ utf8_printf(stderr, "Error %d: %s on [%s]\n",
+ sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
+ zQuery);
+ goto end_data_xfer;
+ }
+ for(k=0; k<2; k++){
+ while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
+ for(i=0; i<n; i++){
+ switch( sqlite3_column_type(pQuery, i) ){
+ case SQLITE_NULL: {
+ sqlite3_bind_null(pInsert, i+1);
+ break;
+ }
+ case SQLITE_INTEGER: {
+ sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
+ break;
+ }
+ case SQLITE_FLOAT: {
+ sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
+ break;
+ }
+ case SQLITE_TEXT: {
+ sqlite3_bind_text(pInsert, i+1,
+ (const char*)sqlite3_column_text(pQuery,i),
+ -1, SQLITE_STATIC);
+ break;
+ }
+ case SQLITE_BLOB: {
+ sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
+ sqlite3_column_bytes(pQuery,i),
+ SQLITE_STATIC);
+ break;
+ }
+ }
+ } /* End for */
+ rc = sqlite3_step(pInsert);
+ if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
+ utf8_printf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
+ sqlite3_errmsg(newDb));
+ }
+ sqlite3_reset(pInsert);
+ cnt++;
+ if( (cnt%spinRate)==0 ){
+ printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
+ fflush(stdout);
+ }
+ } /* End while */
+ if( rc==SQLITE_DONE ) break;
+ sqlite3_finalize(pQuery);
+ sqlite3_free(zQuery);
+ zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
+ zTable);
+ rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
+ if( rc ){
+ utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
+ break;
+ }
+ } /* End for(k=0...) */
+
+end_data_xfer:
+ sqlite3_finalize(pQuery);
+ sqlite3_finalize(pInsert);
+ sqlite3_free(zQuery);
+ sqlite3_free(zInsert);
+}
+
+
+/*
+** Try to transfer all rows of the schema that match zWhere. For
+** each row, invoke xForEach() on the object defined by that row.
+** If an error is encountered while moving forward through the
+** sqlite_master table, try again moving backwards.
+*/
+static void tryToCloneSchema(
+ ShellState *p,
+ sqlite3 *newDb,
+ const char *zWhere,
+ void (*xForEach)(ShellState*,sqlite3*,const char*)
+){
+ sqlite3_stmt *pQuery = 0;
+ char *zQuery = 0;
+ int rc;
+ const unsigned char *zName;
+ const unsigned char *zSql;
+ char *zErrMsg = 0;
+
+ zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
+ " WHERE %s", zWhere);
+ rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
+ if( rc ){
+ utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
+ sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
+ zQuery);
+ goto end_schema_xfer;
+ }
+ while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
+ zName = sqlite3_column_text(pQuery, 0);
+ zSql = sqlite3_column_text(pQuery, 1);
+ printf("%s... ", zName); fflush(stdout);
+ sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
+ if( zErrMsg ){
+ utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
+ sqlite3_free(zErrMsg);
+ zErrMsg = 0;
+ }
+ if( xForEach ){
+ xForEach(p, newDb, (const char*)zName);
+ }
+ printf("done\n");
+ }
+ if( rc!=SQLITE_DONE ){
+ sqlite3_finalize(pQuery);
+ sqlite3_free(zQuery);
+ zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
+ " WHERE %s ORDER BY rowid DESC", zWhere);
+ rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
+ if( rc ){
+ utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
+ sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
+ zQuery);
+ goto end_schema_xfer;
+ }
+ while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
+ zName = sqlite3_column_text(pQuery, 0);
+ zSql = sqlite3_column_text(pQuery, 1);
+ printf("%s... ", zName); fflush(stdout);
+ sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
+ if( zErrMsg ){
+ utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
+ sqlite3_free(zErrMsg);
+ zErrMsg = 0;
+ }
+ if( xForEach ){
+ xForEach(p, newDb, (const char*)zName);
+ }
+ printf("done\n");
+ }
+ }
+end_schema_xfer:
+ sqlite3_finalize(pQuery);
+ sqlite3_free(zQuery);
+}
+
+/*
+** Open a new database file named "zNewDb". Try to recover as much information
+** as possible out of the main database (which might be corrupt) and write it
+** into zNewDb.
+*/
+static void tryToClone(ShellState *p, const char *zNewDb){
+ int rc;
+ sqlite3 *newDb = 0;
+ if( access(zNewDb,0)==0 ){
+ utf8_printf(stderr, "File \"%s\" already exists.\n", zNewDb);
+ return;
+ }
+ rc = sqlite3_open(zNewDb, &newDb);
+ if( rc ){
+ utf8_printf(stderr, "Cannot create output database: %s\n",
+ sqlite3_errmsg(newDb));
+ }else{
+ sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
+ sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
+ tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
+ tryToCloneSchema(p, newDb, "type!='table'", 0);
+ sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
+ sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
+ }
+ sqlite3_close(newDb);
+}
+
+/*
+** Change the output file back to stdout
+*/
+static void output_reset(ShellState *p){
+ if( p->outfile[0]=='|' ){
+#ifndef SQLITE_OMIT_POPEN
+ pclose(p->out);
+#endif
+ }else{
+ output_file_close(p->out);
+ }
+ p->outfile[0] = 0;
+ p->out = stdout;
+}
+
+/*
+** Run an SQL command and return the single integer result.
+*/
+static int db_int(ShellState *p, const char *zSql){
+ sqlite3_stmt *pStmt;
+ int res = 0;
+ sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
+ res = sqlite3_column_int(pStmt,0);
+ }
+ sqlite3_finalize(pStmt);
+ return res;
+}
+
+/*
+** Convert a 2-byte or 4-byte big-endian integer into a native integer
+*/
+static unsigned int get2byteInt(unsigned char *a){
+ return (a[0]<<8) + a[1];
+}
+static unsigned int get4byteInt(unsigned char *a){
+ return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
+}
+
+/*
+** Implementation of the ".info" command.
+**
+** Return 1 on error, 2 to exit, and 0 otherwise.
+*/
+static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
+ static const struct { const char *zName; int ofst; } aField[] = {
+ { "file change counter:", 24 },
+ { "database page count:", 28 },
+ { "freelist page count:", 36 },
+ { "schema cookie:", 40 },
+ { "schema format:", 44 },
+ { "default cache size:", 48 },
+ { "autovacuum top root:", 52 },
+ { "incremental vacuum:", 64 },
+ { "text encoding:", 56 },
+ { "user version:", 60 },
+ { "application id:", 68 },
+ { "software version:", 96 },
+ };
+ static const struct { const char *zName; const char *zSql; } aQuery[] = {
+ { "number of tables:",
+ "SELECT count(*) FROM %s WHERE type='table'" },
+ { "number of indexes:",
+ "SELECT count(*) FROM %s WHERE type='index'" },
+ { "number of triggers:",
+ "SELECT count(*) FROM %s WHERE type='trigger'" },
+ { "number of views:",
+ "SELECT count(*) FROM %s WHERE type='view'" },
+ { "schema size:",
+ "SELECT total(length(sql)) FROM %s" },
+ };
+ int i;
+ char *zSchemaTab;
+ char *zDb = nArg>=2 ? azArg[1] : "main";
+ sqlite3_stmt *pStmt = 0;
+ unsigned char aHdr[100];
+ open_db(p, 0);
+ if( p->db==0 ) return 1;
+ sqlite3_prepare_v2(p->db,"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
+ -1, &pStmt, 0);
+ sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
+ if( sqlite3_step(pStmt)==SQLITE_ROW
+ && sqlite3_column_bytes(pStmt,0)>100
+ ){
+ memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100);
+ sqlite3_finalize(pStmt);
+ }else{
+ raw_printf(stderr, "unable to read database header\n");
+ sqlite3_finalize(pStmt);
+ return 1;
+ }
+ i = get2byteInt(aHdr+16);
+ if( i==1 ) i = 65536;
+ utf8_printf(p->out, "%-20s %d\n", "database page size:", i);
+ utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
+ utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
+ utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
+ for(i=0; i<ArraySize(aField); i++){
+ int ofst = aField[i].ofst;
+ unsigned int val = get4byteInt(aHdr + ofst);
+ utf8_printf(p->out, "%-20s %u", aField[i].zName, val);
+ switch( ofst ){
+ case 56: {
+ if( val==1 ) raw_printf(p->out, " (utf8)");
+ if( val==2 ) raw_printf(p->out, " (utf16le)");
+ if( val==3 ) raw_printf(p->out, " (utf16be)");
+ }
+ }
+ raw_printf(p->out, "\n");
+ }
+ if( zDb==0 ){
+ zSchemaTab = sqlite3_mprintf("main.sqlite_master");
+ }else if( strcmp(zDb,"temp")==0 ){
+ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
+ }else{
+ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
+ }
+ for(i=0; i<ArraySize(aQuery); i++){
+ char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
+ int val = db_int(p, zSql);
+ sqlite3_free(zSql);
+ utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
+ }
+ sqlite3_free(zSchemaTab);
+ return 0;
+}
+
+/*
+** Print the current sqlite3_errmsg() value to stderr and return 1.
+*/
+static int shellDatabaseError(sqlite3 *db){
+ const char *zErr = sqlite3_errmsg(db);
+ utf8_printf(stderr, "Error: %s\n", zErr);
+ return 1;
+}
+
+/*
+** Print an out-of-memory message to stderr and return 1.
+*/
+static int shellNomemError(void){
+ raw_printf(stderr, "Error: out of memory\n");
+ return 1;
+}
+
+/*
+** Compare the pattern in zGlob[] against the text in z[]. Return TRUE
+** if they match and FALSE (0) if they do not match.
+**
+** Globbing rules:
+**
+** '*' Matches any sequence of zero or more characters.
+**
+** '?' Matches exactly one character.
+**
+** [...] Matches one character from the enclosed list of
+** characters.
+**
+** [^...] Matches one character not in the enclosed list.
+**
+** '#' Matches any sequence of one or more digits with an
+** optional + or - sign in front
+**
+** ' ' Any span of whitespace matches any other span of
+** whitespace.
+**
+** Extra whitespace at the end of z[] is ignored.
+*/
+static int testcase_glob(const char *zGlob, const char *z){
+ int c, c2;
+ int invert;
+ int seen;
+
+ while( (c = (*(zGlob++)))!=0 ){
+ if( IsSpace(c) ){
+ if( !IsSpace(*z) ) return 0;
+ while( IsSpace(*zGlob) ) zGlob++;
+ while( IsSpace(*z) ) z++;
+ }else if( c=='*' ){
+ while( (c=(*(zGlob++))) == '*' || c=='?' ){
+ if( c=='?' && (*(z++))==0 ) return 0;
+ }
+ if( c==0 ){
+ return 1;
+ }else if( c=='[' ){
+ while( *z && testcase_glob(zGlob-1,z)==0 ){
+ z++;
+ }
+ return (*z)!=0;
+ }
+ while( (c2 = (*(z++)))!=0 ){
+ while( c2!=c ){
+ c2 = *(z++);
+ if( c2==0 ) return 0;
+ }
+ if( testcase_glob(zGlob,z) ) return 1;
+ }
+ return 0;
+ }else if( c=='?' ){
+ if( (*(z++))==0 ) return 0;
+ }else if( c=='[' ){
+ int prior_c = 0;
+ seen = 0;
+ invert = 0;
+ c = *(z++);
+ if( c==0 ) return 0;
+ c2 = *(zGlob++);
+ if( c2=='^' ){
+ invert = 1;
+ c2 = *(zGlob++);
+ }
+ if( c2==']' ){
+ if( c==']' ) seen = 1;
+ c2 = *(zGlob++);
+ }
+ while( c2 && c2!=']' ){
+ if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
+ c2 = *(zGlob++);
+ if( c>=prior_c && c<=c2 ) seen = 1;
+ prior_c = 0;
+ }else{
+ if( c==c2 ){
+ seen = 1;
+ }
+ prior_c = c2;
+ }
+ c2 = *(zGlob++);
+ }
+ if( c2==0 || (seen ^ invert)==0 ) return 0;
+ }else if( c=='#' ){
+ if( (z[0]=='-' || z[0]=='+') && IsDigit(z[1]) ) z++;
+ if( !IsDigit(z[0]) ) return 0;
+ z++;
+ while( IsDigit(z[0]) ){ z++; }
+ }else{
+ if( c!=(*(z++)) ) return 0;
+ }
+ }
+ while( IsSpace(*z) ){ z++; }
+ return *z==0;
+}
+
+
+/*
+** Compare the string as a command-line option with either one or two
+** initial "-" characters.
+*/
+static int optionMatch(const char *zStr, const char *zOpt){
+ if( zStr[0]!='-' ) return 0;
+ zStr++;
+ if( zStr[0]=='-' ) zStr++;
+ return strcmp(zStr, zOpt)==0;
+}
+
+/*
+** Delete a file.
+*/
+int shellDeleteFile(const char *zFilename){
+ int rc;
+#ifdef _WIN32
+ wchar_t *z = sqlite3_win32_utf8_to_unicode(zFilename);
+ rc = _wunlink(z);
+ sqlite3_free(z);
+#else
+ rc = unlink(zFilename);
+#endif
+ return rc;
+}
+
+
+/*
+** The implementation of SQL scalar function fkey_collate_clause(), used
+** by the ".lint fkey-indexes" command. This scalar function is always
+** called with four arguments - the parent table name, the parent column name,
+** the child table name and the child column name.
+**
+** fkey_collate_clause('parent-tab', 'parent-col', 'child-tab', 'child-col')
+**
+** If either of the named tables or columns do not exist, this function
+** returns an empty string. An empty string is also returned if both tables
+** and columns exist but have the same default collation sequence. Or,
+** if both exist but the default collation sequences are different, this
+** function returns the string " COLLATE <parent-collation>", where
+** <parent-collation> is the default collation sequence of the parent column.
+*/
+static void shellFkeyCollateClause(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ sqlite3 *db = sqlite3_context_db_handle(pCtx);
+ const char *zParent;
+ const char *zParentCol;
+ const char *zParentSeq;
+ const char *zChild;
+ const char *zChildCol;
+ const char *zChildSeq = 0; /* Initialize to avoid false-positive warning */
+ int rc;
+
+ assert( nVal==4 );
+ zParent = (const char*)sqlite3_value_text(apVal[0]);
+ zParentCol = (const char*)sqlite3_value_text(apVal[1]);
+ zChild = (const char*)sqlite3_value_text(apVal[2]);
+ zChildCol = (const char*)sqlite3_value_text(apVal[3]);
+
+ sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
+ rc = sqlite3_table_column_metadata(
+ db, "main", zParent, zParentCol, 0, &zParentSeq, 0, 0, 0
+ );
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_table_column_metadata(
+ db, "main", zChild, zChildCol, 0, &zChildSeq, 0, 0, 0
+ );
+ }
+
+ if( rc==SQLITE_OK && sqlite3_stricmp(zParentSeq, zChildSeq) ){
+ char *z = sqlite3_mprintf(" COLLATE %s", zParentSeq);
+ sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
+ sqlite3_free(z);
+ }
+}
+
+
+/*
+** The implementation of dot-command ".lint fkey-indexes".
+*/
+static int lintFkeyIndexes(
+ ShellState *pState, /* Current shell tool state */
+ char **azArg, /* Array of arguments passed to dot command */
+ int nArg /* Number of entries in azArg[] */
+){
+ sqlite3 *db = pState->db; /* Database handle to query "main" db of */
+ FILE *out = pState->out; /* Stream to write non-error output to */
+ int bVerbose = 0; /* If -verbose is present */
+ int bGroupByParent = 0; /* If -groupbyparent is present */
+ int i; /* To iterate through azArg[] */
+ const char *zIndent = ""; /* How much to indent CREATE INDEX by */
+ int rc; /* Return code */
+ sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
+
+ /*
+ ** This SELECT statement returns one row for each foreign key constraint
+ ** in the schema of the main database. The column values are:
+ **
+ ** 0. The text of an SQL statement similar to:
+ **
+ ** "EXPLAIN QUERY PLAN SELECT rowid FROM child_table WHERE child_key=?"
+ **
+ ** This is the same SELECT that the foreign keys implementation needs
+ ** to run internally on child tables. If there is an index that can
+ ** be used to optimize this query, then it can also be used by the FK
+ ** implementation to optimize DELETE or UPDATE statements on the parent
+ ** table.
+ **
+ ** 1. A GLOB pattern suitable for sqlite3_strglob(). If the plan output by
+ ** the EXPLAIN QUERY PLAN command matches this pattern, then the schema
+ ** contains an index that can be used to optimize the query.
+ **
+ ** 2. Human readable text that describes the child table and columns. e.g.
+ **
+ ** "child_table(child_key1, child_key2)"
+ **
+ ** 3. Human readable text that describes the parent table and columns. e.g.
+ **
+ ** "parent_table(parent_key1, parent_key2)"
+ **
+ ** 4. A full CREATE INDEX statement for an index that could be used to
+ ** optimize DELETE or UPDATE statements on the parent table. e.g.
+ **
+ ** "CREATE INDEX child_table_child_key ON child_table(child_key)"
+ **
+ ** 5. The name of the parent table.
+ **
+ ** These six values are used by the C logic below to generate the report.
+ */
+ const char *zSql =
+ "SELECT "
+ " 'EXPLAIN QUERY PLAN SELECT rowid FROM ' || quote(s.name) || ' WHERE '"
+ " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
+ " || fkey_collate_clause("
+ " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
+ ", "
+ " 'SEARCH TABLE ' || s.name || ' USING COVERING INDEX*('"
+ " || group_concat('*=?', ' AND ') || ')'"
+ ", "
+ " s.name || '(' || group_concat(f.[from], ', ') || ')'"
+ ", "
+ " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
+ ", "
+ " 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
+ " || ' ON ' || quote(s.name) || '('"
+ " || group_concat(quote(f.[from]) ||"
+ " fkey_collate_clause("
+ " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
+ " || ');'"
+ ", "
+ " f.[table] "
+ "FROM sqlite_master AS s, pragma_foreign_key_list(s.name) AS f "
+ "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
+ "GROUP BY s.name, f.id "
+ "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
+ ;
+ const char *zGlobIPK = "SEARCH TABLE * USING INTEGER PRIMARY KEY (rowid=?)";
+
+ for(i=2; i<nArg; i++){
+ int n = (int)strlen(azArg[i]);
+ if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
+ bVerbose = 1;
+ }
+ else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
+ bGroupByParent = 1;
+ zIndent = " ";
+ }
+ else{
+ raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n",
+ azArg[0], azArg[1]
+ );
+ return SQLITE_ERROR;
+ }
+ }
+
+ /* Register the fkey_collate_clause() SQL function */
+ rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
+ 0, shellFkeyCollateClause, 0, 0
+ );
+
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int(pSql, 1, bGroupByParent);
+ }
+
+ if( rc==SQLITE_OK ){
+ int rc2;
+ char *zPrev = 0;
+ while( SQLITE_ROW==sqlite3_step(pSql) ){
+ int res = -1;
+ sqlite3_stmt *pExplain = 0;
+ const char *zEQP = (const char*)sqlite3_column_text(pSql, 0);
+ const char *zGlob = (const char*)sqlite3_column_text(pSql, 1);
+ const char *zFrom = (const char*)sqlite3_column_text(pSql, 2);
+ const char *zTarget = (const char*)sqlite3_column_text(pSql, 3);
+ const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
+ const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
+
+ rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
+ if( rc!=SQLITE_OK ) break;
+ if( SQLITE_ROW==sqlite3_step(pExplain) ){
+ const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
+ res = (
+ 0==sqlite3_strglob(zGlob, zPlan)
+ || 0==sqlite3_strglob(zGlobIPK, zPlan)
+ );
+ }
+ rc = sqlite3_finalize(pExplain);
+ if( rc!=SQLITE_OK ) break;
+
+ if( res<0 ){
+ raw_printf(stderr, "Error: internal error");
+ break;
+ }else{
+ if( bGroupByParent
+ && (bVerbose || res==0)
+ && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
+ ){
+ raw_printf(out, "-- Parent table %s\n", zParent);
+ sqlite3_free(zPrev);
+ zPrev = sqlite3_mprintf("%s", zParent);
+ }
+
+ if( res==0 ){
+ raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
+ }else if( bVerbose ){
+ raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
+ zIndent, zFrom, zTarget
+ );
+ }
+ }
+ }
+ sqlite3_free(zPrev);
+
+ if( rc!=SQLITE_OK ){
+ raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
+ }
+
+ rc2 = sqlite3_finalize(pSql);
+ if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
+ rc = rc2;
+ raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
+ }
+ }else{
+ raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
+ }
+
+ return rc;
+}
+
+/*
+** Implementation of ".lint" dot command.
+*/
+static int lintDotCommand(
+ ShellState *pState, /* Current shell tool state */
+ char **azArg, /* Array of arguments passed to dot command */
+ int nArg /* Number of entries in azArg[] */
+){
+ int n;
+ n = (nArg>=2 ? (int)strlen(azArg[1]) : 0);
+ if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
+ return lintFkeyIndexes(pState, azArg, nArg);
+
+ usage:
+ raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
+ raw_printf(stderr, "Where sub-commands are:\n");
+ raw_printf(stderr, " fkey-indexes\n");
+ return SQLITE_ERROR;
+}
+
+
+/*
+** If an input line begins with "." then invoke this routine to
+** process that line.
+**
+** Return 1 on error, 2 to exit, and 0 otherwise.
+*/
+static int do_meta_command(char *zLine, ShellState *p){
+ int h = 1;
+ int nArg = 0;
+ int n, c;
+ int rc = 0;
+ char *azArg[50];
+
+ /* Parse the input line into tokens.
+ */
+ while( zLine[h] && nArg<ArraySize(azArg) ){
+ while( IsSpace(zLine[h]) ){ h++; }
+ if( zLine[h]==0 ) break;
+ if( zLine[h]=='\'' || zLine[h]=='"' ){
+ int delim = zLine[h++];
+ azArg[nArg++] = &zLine[h];
+ while( zLine[h] && zLine[h]!=delim ){
+ if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
+ h++;
+ }
+ if( zLine[h]==delim ){
+ zLine[h++] = 0;
+ }
+ if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
+ }else{
+ azArg[nArg++] = &zLine[h];
+ while( zLine[h] && !IsSpace(zLine[h]) ){ h++; }
+ if( zLine[h] ) zLine[h++] = 0;
+ resolve_backslashes(azArg[nArg-1]);
+ }
+ }
+
+ /* Process the input line.
+ */
+ if( nArg==0 ) return 0; /* no tokens, no error */
+ n = strlen30(azArg[0]);
+ c = azArg[0][0];
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){
+ if( nArg!=2 ){
+ raw_printf(stderr, "Usage: .auth ON|OFF\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ open_db(p, 0);
+ if( booleanValue(azArg[1]) ){
+ sqlite3_set_authorizer(p->db, shellAuth, p);
+ }else{
+ sqlite3_set_authorizer(p->db, 0, 0);
+ }
+ }else
+#endif
+
+ if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
+ || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
+ ){
+ const char *zDestFile = 0;
+ const char *zDb = 0;
+ sqlite3 *pDest;
+ sqlite3_backup *pBackup;
+ int j;
+ for(j=1; j<nArg; j++){
+ const char *z = azArg[j];
+ if( z[0]=='-' ){
+ while( z[0]=='-' ) z++;
+ /* No options to process at this time */
+ {
+ utf8_printf(stderr, "unknown option: %s\n", azArg[j]);
+ return 1;
+ }
+ }else if( zDestFile==0 ){
+ zDestFile = azArg[j];
+ }else if( zDb==0 ){
+ zDb = zDestFile;
+ zDestFile = azArg[j];
+ }else{
+ raw_printf(stderr, "too many arguments to .backup\n");
+ return 1;
+ }
+ }
+ if( zDestFile==0 ){
+ raw_printf(stderr, "missing FILENAME argument on .backup\n");
+ return 1;
+ }
+ if( zDb==0 ) zDb = "main";
+ rc = sqlite3_open(zDestFile, &pDest);
+ if( rc!=SQLITE_OK ){
+ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
+ sqlite3_close(pDest);
+ return 1;
+ }
+ open_db(p, 0);
+ pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
+ if( pBackup==0 ){
+ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
+ sqlite3_close(pDest);
+ return 1;
+ }
+ while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
+ sqlite3_backup_finish(pBackup);
+ if( rc==SQLITE_DONE ){
+ rc = 0;
+ }else{
+ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
+ rc = 1;
+ }
+ sqlite3_close(pDest);
+ }else
+
+ if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){
+ if( nArg==2 ){
+ bail_on_error = booleanValue(azArg[1]);
+ }else{
+ raw_printf(stderr, "Usage: .bail on|off\n");
+ rc = 1;
+ }
+ }else
+
+ if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){
+ if( nArg==2 ){
+ if( booleanValue(azArg[1]) ){
+ setBinaryMode(p->out, 1);
+ }else{
+ setTextMode(p->out, 1);
+ }
+ }else{
+ raw_printf(stderr, "Usage: .binary on|off\n");
+ rc = 1;
+ }
+ }else
+
+ if( c=='c' && strcmp(azArg[0],"cd")==0 ){
+ if( nArg==2 ){
+#if defined(_WIN32) || defined(WIN32)
+ wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
+ rc = !SetCurrentDirectoryW(z);
+ sqlite3_free(z);
+#else
+ rc = chdir(azArg[1]);
+#endif
+ if( rc ){
+ utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
+ rc = 1;
+ }
+ }else{
+ raw_printf(stderr, "Usage: .cd DIRECTORY\n");
+ rc = 1;
+ }
+ }else
+
+ /* The undocumented ".breakpoint" command causes a call to the no-op
+ ** routine named test_breakpoint().
+ */
+ if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
+ test_breakpoint();
+ }else
+
+ if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){
+ if( nArg==2 ){
+ setOrClearFlag(p, SHFLG_CountChanges, azArg[1]);
+ }else{
+ raw_printf(stderr, "Usage: .changes on|off\n");
+ rc = 1;
+ }
+ }else
+
+ /* Cancel output redirection, if it is currently set (by .testcase)
+ ** Then read the content of the testcase-out.txt file and compare against
+ ** azArg[1]. If there are differences, report an error and exit.
+ */
+ if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
+ char *zRes = 0;
+ output_reset(p);
+ if( nArg!=2 ){
+ raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
+ rc = 2;
+ }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
+ raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
+ rc = 2;
+ }else if( testcase_glob(azArg[1],zRes)==0 ){
+ utf8_printf(stderr,
+ "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
+ p->zTestcase, azArg[1], zRes);
+ rc = 1;
+ }else{
+ utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
+ p->nCheck++;
+ }
+ sqlite3_free(zRes);
+ }else
+
+ if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
+ if( nArg==2 ){
+ tryToClone(p, azArg[1]);
+ }else{
+ raw_printf(stderr, "Usage: .clone FILENAME\n");
+ rc = 1;
+ }
+ }else
+
+ if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
+ ShellState data;
+ char *zErrMsg = 0;
+ open_db(p, 0);
+ memcpy(&data, p, sizeof(data));
+ data.showHeader = 0;
+ data.cMode = data.mode = MODE_List;
+ sqlite3_snprintf(sizeof(data.colSeparator),data.colSeparator,": ");
+ data.cnt = 0;
+ sqlite3_exec(p->db, "SELECT name, file FROM pragma_database_list",
+ callback, &data, &zErrMsg);
+ if( zErrMsg ){
+ utf8_printf(stderr,"Error: %s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ rc = 1;
+ }
+ }else
+
+ if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){
+ rc = shell_dbinfo_command(p, nArg, azArg);
+ }else
+
+ if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
+ const char *zLike = 0;
+ int i;
+ int savedShowHeader = p->showHeader;
+ ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines);
+ for(i=1; i<nArg; i++){
+ if( azArg[i][0]=='-' ){
+ const char *z = azArg[i]+1;
+ if( z[0]=='-' ) z++;
+ if( strcmp(z,"preserve-rowids")==0 ){
+#ifdef SQLITE_OMIT_VIRTUALTABLE
+ raw_printf(stderr, "The --preserve-rowids option is not compatible"
+ " with SQLITE_OMIT_VIRTUALTABLE\n");
+ rc = 1;
+ goto meta_command_exit;
+#else
+ ShellSetFlag(p, SHFLG_PreserveRowid);
+#endif
+ }else
+ if( strcmp(z,"newlines")==0 ){
+ ShellSetFlag(p, SHFLG_Newlines);
+ }else
+ {
+ raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }else if( zLike ){
+ raw_printf(stderr, "Usage: .dump ?--preserve-rowids? "
+ "?--newlines? ?LIKE-PATTERN?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }else{
+ zLike = azArg[i];
+ }
+ }
+ open_db(p, 0);
+ /* When playing back a "dump", the content might appear in an order
+ ** which causes immediate foreign key constraints to be violated.
+ ** So disable foreign-key constraint enforcement to prevent problems. */
+ raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
+ raw_printf(p->out, "BEGIN TRANSACTION;\n");
+ p->writableSchema = 0;
+ p->showHeader = 0;
+ /* Set writable_schema=ON since doing so forces SQLite to initialize
+ ** as much of the schema as it can even if the sqlite_master table is
+ ** corrupt. */
+ sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
+ p->nErr = 0;
+ if( zLike==0 ){
+ run_schema_dump_query(p,
+ "SELECT name, type, sql FROM sqlite_master "
+ "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
+ );
+ run_schema_dump_query(p,
+ "SELECT name, type, sql FROM sqlite_master "
+ "WHERE name=='sqlite_sequence'"
+ );
+ run_table_dump_query(p,
+ "SELECT sql FROM sqlite_master "
+ "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
+ );
+ }else{
+ char *zSql;
+ zSql = sqlite3_mprintf(
+ "SELECT name, type, sql FROM sqlite_master "
+ "WHERE tbl_name LIKE %Q AND type=='table'"
+ " AND sql NOT NULL", zLike);
+ run_schema_dump_query(p,zSql);
+ sqlite3_free(zSql);
+ zSql = sqlite3_mprintf(
+ "SELECT sql FROM sqlite_master "
+ "WHERE sql NOT NULL"
+ " AND type IN ('index','trigger','view')"
+ " AND tbl_name LIKE %Q", zLike);
+ run_table_dump_query(p, zSql, 0);
+ sqlite3_free(zSql);
+ }
+ if( p->writableSchema ){
+ raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
+ p->writableSchema = 0;
+ }
+ sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
+ sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
+ raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
+ p->showHeader = savedShowHeader;
+ }else
+
+ if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
+ if( nArg==2 ){
+ setOrClearFlag(p, SHFLG_Echo, azArg[1]);
+ }else{
+ raw_printf(stderr, "Usage: .echo on|off\n");
+ rc = 1;
+ }
+ }else
+
+ if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
+ if( nArg==2 ){
+ if( strcmp(azArg[1],"full")==0 ){
+ p->autoEQP = 2;
+ }else{
+ p->autoEQP = booleanValue(azArg[1]);
+ }
+ }else{
+ raw_printf(stderr, "Usage: .eqp on|off|full\n");
+ rc = 1;
+ }
+ }else
+
+ if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
+ if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
+ rc = 2;
+ }else
+
+ /* The ".explain" command is automatic now. It is largely pointless. It
+ ** retained purely for backwards compatibility */
+ if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
+ int val = 1;
+ if( nArg>=2 ){
+ if( strcmp(azArg[1],"auto")==0 ){
+ val = 99;
+ }else{
+ val = booleanValue(azArg[1]);
+ }
+ }
+ if( val==1 && p->mode!=MODE_Explain ){
+ p->normalMode = p->mode;
+ p->mode = MODE_Explain;
+ p->autoExplain = 0;
+ }else if( val==0 ){
+ if( p->mode==MODE_Explain ) p->mode = p->normalMode;
+ p->autoExplain = 0;
+ }else if( val==99 ){
+ if( p->mode==MODE_Explain ) p->mode = p->normalMode;
+ p->autoExplain = 1;
+ }
+ }else
+
+ if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){
+ ShellState data;
+ char *zErrMsg = 0;
+ int doStats = 0;
+ memcpy(&data, p, sizeof(data));
+ data.showHeader = 0;
+ data.cMode = data.mode = MODE_Semi;
+ if( nArg==2 && optionMatch(azArg[1], "indent") ){
+ data.cMode = data.mode = MODE_Pretty;
+ nArg = 1;
+ }
+ if( nArg!=1 ){
+ raw_printf(stderr, "Usage: .fullschema ?--indent?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ open_db(p, 0);
+ rc = sqlite3_exec(p->db,
+ "SELECT sql FROM"
+ " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
+ " FROM sqlite_master UNION ALL"
+ " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
+ "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
+ "ORDER BY rowid",
+ callback, &data, &zErrMsg
+ );
+ if( rc==SQLITE_OK ){
+ sqlite3_stmt *pStmt;
+ rc = sqlite3_prepare_v2(p->db,
+ "SELECT rowid FROM sqlite_master"
+ " WHERE name GLOB 'sqlite_stat[134]'",
+ -1, &pStmt, 0);
+ doStats = sqlite3_step(pStmt)==SQLITE_ROW;
+ sqlite3_finalize(pStmt);
+ }
+ if( doStats==0 ){
+ raw_printf(p->out, "/* No STAT tables available */\n");
+ }else{
+ raw_printf(p->out, "ANALYZE sqlite_master;\n");
+ sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'",
+ callback, &data, &zErrMsg);
+ data.cMode = data.mode = MODE_Insert;
+ data.zDestTable = "sqlite_stat1";
+ shell_exec(p->db, "SELECT * FROM sqlite_stat1",
+ shell_callback, &data,&zErrMsg);
+ data.zDestTable = "sqlite_stat3";
+ shell_exec(p->db, "SELECT * FROM sqlite_stat3",
+ shell_callback, &data,&zErrMsg);
+ data.zDestTable = "sqlite_stat4";
+ shell_exec(p->db, "SELECT * FROM sqlite_stat4",
+ shell_callback, &data, &zErrMsg);
+ raw_printf(p->out, "ANALYZE sqlite_master;\n");
+ }
+ }else
+
+ if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){
+ if( nArg==2 ){
+ p->showHeader = booleanValue(azArg[1]);
+ }else{
+ raw_printf(stderr, "Usage: .headers on|off\n");
+ rc = 1;
+ }
+ }else
+
+ if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
+ utf8_printf(p->out, "%s", zHelp);
+ }else
+
+ if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
+ char *zTable; /* Insert data into this table */
+ char *zFile; /* Name of file to extra content from */
+ sqlite3_stmt *pStmt = NULL; /* A statement */
+ int nCol; /* Number of columns in the table */
+ int nByte; /* Number of bytes in an SQL string */
+ int i, j; /* Loop counters */
+ int needCommit; /* True to COMMIT or ROLLBACK at end */
+ int nSep; /* Number of bytes in p->colSeparator[] */
+ char *zSql; /* An SQL statement */
+ ImportCtx sCtx; /* Reader context */
+ char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
+ int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */
+
+ if( nArg!=3 ){
+ raw_printf(stderr, "Usage: .import FILE TABLE\n");
+ goto meta_command_exit;
+ }
+ zFile = azArg[1];
+ zTable = azArg[2];
+ seenInterrupt = 0;
+ memset(&sCtx, 0, sizeof(sCtx));
+ open_db(p, 0);
+ nSep = strlen30(p->colSeparator);
+ if( nSep==0 ){
+ raw_printf(stderr,
+ "Error: non-null column separator required for import\n");
+ return 1;
+ }
+ if( nSep>1 ){
+ raw_printf(stderr, "Error: multi-character column separators not allowed"
+ " for import\n");
+ return 1;
+ }
+ nSep = strlen30(p->rowSeparator);
+ if( nSep==0 ){
+ raw_printf(stderr, "Error: non-null row separator required for import\n");
+ return 1;
+ }
+ if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
+ /* When importing CSV (only), if the row separator is set to the
+ ** default output row separator, change it to the default input
+ ** row separator. This avoids having to maintain different input
+ ** and output row separators. */
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
+ nSep = strlen30(p->rowSeparator);
+ }
+ if( nSep>1 ){
+ raw_printf(stderr, "Error: multi-character row separators not allowed"
+ " for import\n");
+ return 1;
+ }
+ sCtx.zFile = zFile;
+ sCtx.nLine = 1;
+ if( sCtx.zFile[0]=='|' ){
+#ifdef SQLITE_OMIT_POPEN
+ raw_printf(stderr, "Error: pipes are not supported in this OS\n");
+ return 1;
+#else
+ sCtx.in = popen(sCtx.zFile+1, "r");
+ sCtx.zFile = "<pipe>";
+ xCloser = pclose;
+#endif
+ }else{
+ sCtx.in = fopen(sCtx.zFile, "rb");
+ xCloser = fclose;
+ }
+ if( p->mode==MODE_Ascii ){
+ xRead = ascii_read_one_field;
+ }else{
+ xRead = csv_read_one_field;
+ }
+ if( sCtx.in==0 ){
+ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
+ return 1;
+ }
+ sCtx.cColSep = p->colSeparator[0];
+ sCtx.cRowSep = p->rowSeparator[0];
+ zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
+ if( zSql==0 ){
+ raw_printf(stderr, "Error: out of memory\n");
+ xCloser(sCtx.in);
+ return 1;
+ }
+ nByte = strlen30(zSql);
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
+ if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
+ char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
+ char cSep = '(';
+ while( xRead(&sCtx) ){
+ zCreate = sqlite3_mprintf("%z%c\n \"%w\" TEXT", zCreate, cSep, sCtx.z);
+ cSep = ',';
+ if( sCtx.cTerm!=sCtx.cColSep ) break;
+ }
+ if( cSep=='(' ){
+ sqlite3_free(zCreate);
+ sqlite3_free(sCtx.z);
+ xCloser(sCtx.in);
+ utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
+ return 1;
+ }
+ zCreate = sqlite3_mprintf("%z\n)", zCreate);
+ rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
+ sqlite3_free(zCreate);
+ if( rc ){
+ utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
+ sqlite3_errmsg(p->db));
+ sqlite3_free(sCtx.z);
+ xCloser(sCtx.in);
+ return 1;
+ }
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ }
+ sqlite3_free(zSql);
+ if( rc ){
+ if (pStmt) sqlite3_finalize(pStmt);
+ utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
+ xCloser(sCtx.in);
+ return 1;
+ }
+ nCol = sqlite3_column_count(pStmt);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ if( nCol==0 ) return 0; /* no columns, no error */
+ zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
+ if( zSql==0 ){
+ raw_printf(stderr, "Error: out of memory\n");
+ xCloser(sCtx.in);
+ return 1;
+ }
+ sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
+ j = strlen30(zSql);
+ for(i=1; i<nCol; i++){
+ zSql[j++] = ',';
+ zSql[j++] = '?';
+ }
+ zSql[j++] = ')';
+ zSql[j] = 0;
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ){
+ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
+ if (pStmt) sqlite3_finalize(pStmt);
+ xCloser(sCtx.in);
+ return 1;
+ }
+ needCommit = sqlite3_get_autocommit(p->db);
+ if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
+ do{
+ int startLine = sCtx.nLine;
+ for(i=0; i<nCol; i++){
+ char *z = xRead(&sCtx);
+ /*
+ ** Did we reach end-of-file before finding any columns?
+ ** If so, stop instead of NULL filling the remaining columns.
+ */
+ if( z==0 && i==0 ) break;
+ /*
+ ** Did we reach end-of-file OR end-of-line before finding any
+ ** columns in ASCII mode? If so, stop instead of NULL filling
+ ** the remaining columns.
+ */
+ if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
+ sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
+ if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
+ utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
+ "filling the rest with NULL\n",
+ sCtx.zFile, startLine, nCol, i+1);
+ i += 2;
+ while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
+ }
+ }
+ if( sCtx.cTerm==sCtx.cColSep ){
+ do{
+ xRead(&sCtx);
+ i++;
+ }while( sCtx.cTerm==sCtx.cColSep );
+ utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
+ "extras ignored\n",
+ sCtx.zFile, startLine, nCol, i);
+ }
+ if( i>=nCol ){
+ sqlite3_step(pStmt);
+ rc = sqlite3_reset(pStmt);
+ if( rc!=SQLITE_OK ){
+ utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
+ startLine, sqlite3_errmsg(p->db));
+ }
+ }
+ }while( sCtx.cTerm!=EOF );
+
+ xCloser(sCtx.in);
+ sqlite3_free(sCtx.z);
+ sqlite3_finalize(pStmt);
+ if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
+ }else
+
+#ifndef SQLITE_UNTESTABLE
+ if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
+ char *zSql;
+ char *zCollist = 0;
+ sqlite3_stmt *pStmt;
+ int tnum = 0;
+ int i;
+ if( nArg!=3 ){
+ utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ open_db(p, 0);
+ zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_master"
+ " WHERE name='%q' AND type='index'", azArg[1]);
+ sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ tnum = sqlite3_column_int(pStmt, 0);
+ }
+ sqlite3_finalize(pStmt);
+ if( tnum==0 ){
+ utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ i = 0;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ char zLabel[20];
+ const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
+ i++;
+ if( zCol==0 ){
+ if( sqlite3_column_int(pStmt,1)==-1 ){
+ zCol = "_ROWID_";
+ }else{
+ sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i);
+ zCol = zLabel;
+ }
+ }
+ if( zCollist==0 ){
+ zCollist = sqlite3_mprintf("\"%w\"", zCol);
+ }else{
+ zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
+ }
+ }
+ sqlite3_finalize(pStmt);
+ zSql = sqlite3_mprintf(
+ "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%s))WITHOUT ROWID",
+ azArg[2], zCollist, zCollist);
+ sqlite3_free(zCollist);
+ rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
+ if( rc ){
+ utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
+ }else{
+ utf8_printf(stdout, "%s;\n", zSql);
+ raw_printf(stdout,
+ "WARNING: writing to an imposter table will corrupt the index!\n"
+ );
+ }
+ }else{
+ raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
+ rc = 1;
+ }
+ sqlite3_free(zSql);
+ }else
+#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
+
+#ifdef SQLITE_ENABLE_IOTRACE
+ if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
+ SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
+ if( iotrace && iotrace!=stdout ) fclose(iotrace);
+ iotrace = 0;
+ if( nArg<2 ){
+ sqlite3IoTrace = 0;
+ }else if( strcmp(azArg[1], "-")==0 ){
+ sqlite3IoTrace = iotracePrintf;
+ iotrace = stdout;
+ }else{
+ iotrace = fopen(azArg[1], "w");
+ if( iotrace==0 ){
+ utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
+ sqlite3IoTrace = 0;
+ rc = 1;
+ }else{
+ sqlite3IoTrace = iotracePrintf;
+ }
+ }
+ }else
+#endif
+
+ if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){
+ static const struct {
+ const char *zLimitName; /* Name of a limit */
+ int limitCode; /* Integer code for that limit */
+ } aLimit[] = {
+ { "length", SQLITE_LIMIT_LENGTH },
+ { "sql_length", SQLITE_LIMIT_SQL_LENGTH },
+ { "column", SQLITE_LIMIT_COLUMN },
+ { "expr_depth", SQLITE_LIMIT_EXPR_DEPTH },
+ { "compound_select", SQLITE_LIMIT_COMPOUND_SELECT },
+ { "vdbe_op", SQLITE_LIMIT_VDBE_OP },
+ { "function_arg", SQLITE_LIMIT_FUNCTION_ARG },
+ { "attached", SQLITE_LIMIT_ATTACHED },
+ { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH },
+ { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER },
+ { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH },
+ { "worker_threads", SQLITE_LIMIT_WORKER_THREADS },
+ };
+ int i, n2;
+ open_db(p, 0);
+ if( nArg==1 ){
+ for(i=0; i<ArraySize(aLimit); i++){
+ printf("%20s %d\n", aLimit[i].zLimitName,
+ sqlite3_limit(p->db, aLimit[i].limitCode, -1));
+ }
+ }else if( nArg>3 ){
+ raw_printf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }else{
+ int iLimit = -1;
+ n2 = strlen30(azArg[1]);
+ for(i=0; i<ArraySize(aLimit); i++){
+ if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
+ if( iLimit<0 ){
+ iLimit = i;
+ }else{
+ utf8_printf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }
+ }
+ if( iLimit<0 ){
+ utf8_printf(stderr, "unknown limit: \"%s\"\n"
+ "enter \".limits\" with no arguments for a list.\n",
+ azArg[1]);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( nArg==3 ){
+ sqlite3_limit(p->db, aLimit[iLimit].limitCode,
+ (int)integerValue(azArg[2]));
+ }
+ printf("%20s %d\n", aLimit[iLimit].zLimitName,
+ sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
+ }
+ }else
+
+ if( c=='l' && n>2 && strncmp(azArg[0], "lint", n)==0 ){
+ open_db(p, 0);
+ lintDotCommand(p, azArg, nArg);
+ }else
+
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
+ const char *zFile, *zProc;
+ char *zErrMsg = 0;
+ if( nArg<2 ){
+ raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ zFile = azArg[1];
+ zProc = nArg>=3 ? azArg[2] : 0;
+ open_db(p, 0);
+ rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
+ if( rc!=SQLITE_OK ){
+ utf8_printf(stderr, "Error: %s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ rc = 1;
+ }
+ }else
+#endif
+
+ if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
+ if( nArg!=2 ){
+ raw_printf(stderr, "Usage: .log FILENAME\n");
+ rc = 1;
+ }else{
+ const char *zFile = azArg[1];
+ output_file_close(p->pLog);
+ p->pLog = output_file_open(zFile);
+ }
+ }else
+
+ if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
+ const char *zMode = nArg>=2 ? azArg[1] : "";
+ int n2 = (int)strlen(zMode);
+ int c2 = zMode[0];
+ if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
+ p->mode = MODE_Line;
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
+ }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
+ p->mode = MODE_Column;
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
+ }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
+ p->mode = MODE_List;
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
+ }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
+ p->mode = MODE_Html;
+ }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
+ p->mode = MODE_Tcl;
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
+ }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
+ p->mode = MODE_Csv;
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
+ }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
+ p->mode = MODE_List;
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
+ }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
+ p->mode = MODE_Insert;
+ set_table_name(p, nArg>=3 ? azArg[2] : "table");
+ }else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){
+ p->mode = MODE_Quote;
+ }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
+ p->mode = MODE_Ascii;
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
+ }else if( nArg==1 ){
+ raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
+ }else{
+ raw_printf(stderr, "Error: mode should be one of: "
+ "ascii column csv html insert line list quote tabs tcl\n");
+ rc = 1;
+ }
+ p->cMode = p->mode;
+ }else
+
+ if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
+ if( nArg==2 ){
+ sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
+ "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
+ }else{
+ raw_printf(stderr, "Usage: .nullvalue STRING\n");
+ rc = 1;
+ }
+ }else
+
+ if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
+ char *zNewFilename; /* Name of the database file to open */
+ int iName = 1; /* Index in azArg[] of the filename */
+ int newFlag = 0; /* True to delete file before opening */
+ /* Close the existing database */
+ session_close_all(p);
+ sqlite3_close(p->db);
+ p->db = 0;
+ p->zDbFilename = 0;
+ sqlite3_free(p->zFreeOnClose);
+ p->zFreeOnClose = 0;
+ /* Check for command-line arguments */
+ for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){
+ const char *z = azArg[iName];
+ if( optionMatch(z,"new") ){
+ newFlag = 1;
+ }else if( z[0]=='-' ){
+ utf8_printf(stderr, "unknown option: %s\n", z);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }
+ /* If a filename is specified, try to open it first */
+ zNewFilename = nArg>iName ? sqlite3_mprintf("%s", azArg[iName]) : 0;
+ if( zNewFilename ){
+ if( newFlag ) shellDeleteFile(zNewFilename);
+ p->zDbFilename = zNewFilename;
+ open_db(p, 1);
+ if( p->db==0 ){
+ utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename);
+ sqlite3_free(zNewFilename);
+ }else{
+ p->zFreeOnClose = zNewFilename;
+ }
+ }
+ if( p->db==0 ){
+ /* As a fall-back open a TEMP database */
+ p->zDbFilename = 0;
+ open_db(p, 0);
+ }
+ }else
+
+ if( c=='o'
+ && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0)
+ ){
+ const char *zFile = nArg>=2 ? azArg[1] : "stdout";
+ if( nArg>2 ){
+ utf8_printf(stderr, "Usage: .%s FILE\n", azArg[0]);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( n>1 && strncmp(azArg[0], "once", n)==0 ){
+ if( nArg<2 ){
+ raw_printf(stderr, "Usage: .once FILE\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ p->outCount = 2;
+ }else{
+ p->outCount = 0;
+ }
+ output_reset(p);
+ if( zFile[0]=='|' ){
+#ifdef SQLITE_OMIT_POPEN
+ raw_printf(stderr, "Error: pipes are not supported in this OS\n");
+ rc = 1;
+ p->out = stdout;
+#else
+ p->out = popen(zFile + 1, "w");
+ if( p->out==0 ){
+ utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
+ p->out = stdout;
+ rc = 1;
+ }else{
+ sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
+ }
+#endif
+ }else{
+ p->out = output_file_open(zFile);
+ if( p->out==0 ){
+ if( strcmp(zFile,"off")!=0 ){
+ utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
+ }
+ p->out = stdout;
+ rc = 1;
+ } else {
+ sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
+ }
+ }
+ }else
+
+ if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){
+ int i;
+ for(i=1; i<nArg; i++){
+ if( i>1 ) raw_printf(p->out, " ");
+ utf8_printf(p->out, "%s", azArg[i]);
+ }
+ raw_printf(p->out, "\n");
+ }else
+
+ if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){
+ if( nArg >= 2) {
+ strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
+ }
+ if( nArg >= 3) {
+ strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
+ }
+ }else
+
+ if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
+ rc = 2;
+ }else
+
+ if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
+ FILE *alt;
+ if( nArg!=2 ){
+ raw_printf(stderr, "Usage: .read FILE\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ alt = fopen(azArg[1], "rb");
+ if( alt==0 ){
+ utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
+ rc = 1;
+ }else{
+ rc = process_input(p, alt);
+ fclose(alt);
+ }
+ }else
+
+ if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
+ const char *zSrcFile;
+ const char *zDb;
+ sqlite3 *pSrc;
+ sqlite3_backup *pBackup;
+ int nTimeout = 0;
+
+ if( nArg==2 ){
+ zSrcFile = azArg[1];
+ zDb = "main";
+ }else if( nArg==3 ){
+ zSrcFile = azArg[2];
+ zDb = azArg[1];
+ }else{
+ raw_printf(stderr, "Usage: .restore ?DB? FILE\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ rc = sqlite3_open(zSrcFile, &pSrc);
+ if( rc!=SQLITE_OK ){
+ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
+ sqlite3_close(pSrc);
+ return 1;
+ }
+ open_db(p, 0);
+ pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
+ if( pBackup==0 ){
+ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
+ sqlite3_close(pSrc);
+ return 1;
+ }
+ while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
+ || rc==SQLITE_BUSY ){
+ if( rc==SQLITE_BUSY ){
+ if( nTimeout++ >= 3 ) break;
+ sqlite3_sleep(100);
+ }
+ }
+ sqlite3_backup_finish(pBackup);
+ if( rc==SQLITE_DONE ){
+ rc = 0;
+ }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
+ raw_printf(stderr, "Error: source database is busy\n");
+ rc = 1;
+ }else{
+ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
+ rc = 1;
+ }
+ sqlite3_close(pSrc);
+ }else
+
+
+ if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
+ if( nArg==2 ){
+ p->scanstatsOn = booleanValue(azArg[1]);
+#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
+ raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
+#endif
+ }else{
+ raw_printf(stderr, "Usage: .scanstats on|off\n");
+ rc = 1;
+ }
+ }else
+
+ if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
+ ShellText sSelect;
+ ShellState data;
+ char *zErrMsg = 0;
+ const char *zDiv = 0;
+ int iSchema = 0;
+
+ open_db(p, 0);
+ memcpy(&data, p, sizeof(data));
+ data.showHeader = 0;
+ data.cMode = data.mode = MODE_Semi;
+ initText(&sSelect);
+ if( nArg>=2 && optionMatch(azArg[1], "indent") ){
+ data.cMode = data.mode = MODE_Pretty;
+ nArg--;
+ if( nArg==2 ) azArg[1] = azArg[2];
+ }
+ if( nArg==2 && azArg[1][0]!='-' ){
+ int i;
+ for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
+ if( strcmp(azArg[1],"sqlite_master")==0 ){
+ char *new_argv[2], *new_colv[2];
+ new_argv[0] = "CREATE TABLE sqlite_master (\n"
+ " type text,\n"
+ " name text,\n"
+ " tbl_name text,\n"
+ " rootpage integer,\n"
+ " sql text\n"
+ ")";
+ new_argv[1] = 0;
+ new_colv[0] = "sql";
+ new_colv[1] = 0;
+ callback(&data, 1, new_argv, new_colv);
+ rc = SQLITE_OK;
+ }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
+ char *new_argv[2], *new_colv[2];
+ new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
+ " type text,\n"
+ " name text,\n"
+ " tbl_name text,\n"
+ " rootpage integer,\n"
+ " sql text\n"
+ ")";
+ new_argv[1] = 0;
+ new_colv[0] = "sql";
+ new_colv[1] = 0;
+ callback(&data, 1, new_argv, new_colv);
+ rc = SQLITE_OK;
+ }else{
+ zDiv = "(";
+ }
+ }else if( nArg==1 ){
+ zDiv = "(";
+ }else{
+ raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( zDiv ){
+ sqlite3_stmt *pStmt = 0;
+ rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
+ -1, &pStmt, 0);
+ if( rc ){
+ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
+ sqlite3_finalize(pStmt);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ appendText(&sSelect, "SELECT sql FROM", 0);
+ iSchema = 0;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
+ char zScNum[30];
+ sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
+ appendText(&sSelect, zDiv, 0);
+ zDiv = " UNION ALL ";
+ if( strcmp(zDb, "main")!=0 ){
+ appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
+ appendText(&sSelect, zDb, '"');
+ appendText(&sSelect, ") AS sql, type, tbl_name, name, rowid,", 0);
+ appendText(&sSelect, zScNum, 0);
+ appendText(&sSelect, " AS snum, ", 0);
+ appendText(&sSelect, zDb, '\'');
+ appendText(&sSelect, " AS sname FROM ", 0);
+ appendText(&sSelect, zDb, '"');
+ appendText(&sSelect, ".sqlite_master", 0);
+ }else{
+ appendText(&sSelect, "SELECT sql, type, tbl_name, name, rowid, ", 0);
+ appendText(&sSelect, zScNum, 0);
+ appendText(&sSelect, " AS snum, 'main' AS sname FROM sqlite_master",0);
+ }
+ }
+ sqlite3_finalize(pStmt);
+ appendText(&sSelect, ") WHERE ", 0);
+ if( nArg>1 ){
+ char *zQarg = sqlite3_mprintf("%Q", azArg[1]);
+ if( strchr(azArg[1], '.') ){
+ appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
+ }else{
+ appendText(&sSelect, "lower(tbl_name)", 0);
+ }
+ appendText(&sSelect, strchr(azArg[1], '*') ? " GLOB " : " LIKE ", 0);
+ appendText(&sSelect, zQarg, 0);
+ appendText(&sSelect, " AND ", 0);
+ sqlite3_free(zQarg);
+ }
+ appendText(&sSelect, "type!='meta' AND sql IS NOT NULL"
+ " ORDER BY snum, rowid", 0);
+ rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
+ freeText(&sSelect);
+ }
+ if( zErrMsg ){
+ utf8_printf(stderr,"Error: %s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ rc = 1;
+ }else if( rc != SQLITE_OK ){
+ raw_printf(stderr,"Error: querying schema information\n");
+ rc = 1;
+ }else{
+ rc = 0;
+ }
+ }else
+
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
+ if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
+ sqlite3SelectTrace = (int)integerValue(azArg[1]);
+ }else
+#endif
+
+#if defined(SQLITE_ENABLE_SESSION)
+ if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){
+ OpenSession *pSession = &p->aSession[0];
+ char **azCmd = &azArg[1];
+ int iSes = 0;
+ int nCmd = nArg - 1;
+ int i;
+ if( nArg<=1 ) goto session_syntax_error;
+ open_db(p, 0);
+ if( nArg>=3 ){
+ for(iSes=0; iSes<p->nSession; iSes++){
+ if( strcmp(p->aSession[iSes].zName, azArg[1])==0 ) break;
+ }
+ if( iSes<p->nSession ){
+ pSession = &p->aSession[iSes];
+ azCmd++;
+ nCmd--;
+ }else{
+ pSession = &p->aSession[0];
+ iSes = 0;
+ }
+ }
+
+ /* .session attach TABLE
+ ** Invoke the sqlite3session_attach() interface to attach a particular
+ ** table so that it is never filtered.
+ */
+ if( strcmp(azCmd[0],"attach")==0 ){
+ if( nCmd!=2 ) goto session_syntax_error;
+ if( pSession->p==0 ){
+ session_not_open:
+ raw_printf(stderr, "ERROR: No sessions are open\n");
+ }else{
+ rc = sqlite3session_attach(pSession->p, azCmd[1]);
+ if( rc ){
+ raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc);
+ rc = 0;
+ }
+ }
+ }else
+
+ /* .session changeset FILE
+ ** .session patchset FILE
+ ** Write a changeset or patchset into a file. The file is overwritten.
+ */
+ if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){
+ FILE *out = 0;
+ if( nCmd!=2 ) goto session_syntax_error;
+ if( pSession->p==0 ) goto session_not_open;
+ out = fopen(azCmd[1], "wb");
+ if( out==0 ){
+ utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", azCmd[1]);
+ }else{
+ int szChng;
+ void *pChng;
+ if( azCmd[0][0]=='c' ){
+ rc = sqlite3session_changeset(pSession->p, &szChng, &pChng);
+ }else{
+ rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
+ }
+ if( rc ){
+ printf("Error: error code %d\n", rc);
+ rc = 0;
+ }
+ if( pChng
+ && fwrite(pChng, szChng, 1, out)!=1 ){
+ raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n",
+ szChng);
+ }
+ sqlite3_free(pChng);
+ fclose(out);
+ }
+ }else
+
+ /* .session close
+ ** Close the identified session
+ */
+ if( strcmp(azCmd[0], "close")==0 ){
+ if( nCmd!=1 ) goto session_syntax_error;
+ if( p->nSession ){
+ session_close(pSession);
+ p->aSession[iSes] = p->aSession[--p->nSession];
+ }
+ }else
+
+ /* .session enable ?BOOLEAN?
+ ** Query or set the enable flag
+ */
+ if( strcmp(azCmd[0], "enable")==0 ){
+ int ii;
+ if( nCmd>2 ) goto session_syntax_error;
+ ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
+ if( p->nSession ){
+ ii = sqlite3session_enable(pSession->p, ii);
+ utf8_printf(p->out, "session %s enable flag = %d\n",
+ pSession->zName, ii);
+ }
+ }else
+
+ /* .session filter GLOB ....
+ ** Set a list of GLOB patterns of table names to be excluded.
+ */
+ if( strcmp(azCmd[0], "filter")==0 ){
+ int ii, nByte;
+ if( nCmd<2 ) goto session_syntax_error;
+ if( p->nSession ){
+ for(ii=0; ii<pSession->nFilter; ii++){
+ sqlite3_free(pSession->azFilter[ii]);
+ }
+ sqlite3_free(pSession->azFilter);
+ nByte = sizeof(pSession->azFilter[0])*(nCmd-1);
+ pSession->azFilter = sqlite3_malloc( nByte );
+ if( pSession->azFilter==0 ){
+ raw_printf(stderr, "Error: out or memory\n");
+ exit(1);
+ }
+ for(ii=1; ii<nCmd; ii++){
+ pSession->azFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]);
+ }
+ pSession->nFilter = ii-1;
+ }
+ }else
+
+ /* .session indirect ?BOOLEAN?
+ ** Query or set the indirect flag
+ */
+ if( strcmp(azCmd[0], "indirect")==0 ){
+ int ii;
+ if( nCmd>2 ) goto session_syntax_error;
+ ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
+ if( p->nSession ){
+ ii = sqlite3session_indirect(pSession->p, ii);
+ utf8_printf(p->out, "session %s indirect flag = %d\n",
+ pSession->zName, ii);
+ }
+ }else
+
+ /* .session isempty
+ ** Determine if the session is empty
+ */
+ if( strcmp(azCmd[0], "isempty")==0 ){
+ int ii;
+ if( nCmd!=1 ) goto session_syntax_error;
+ if( p->nSession ){
+ ii = sqlite3session_isempty(pSession->p);
+ utf8_printf(p->out, "session %s isempty flag = %d\n",
+ pSession->zName, ii);
+ }
+ }else
+
+ /* .session list
+ ** List all currently open sessions
+ */
+ if( strcmp(azCmd[0],"list")==0 ){
+ for(i=0; i<p->nSession; i++){
+ utf8_printf(p->out, "%d %s\n", i, p->aSession[i].zName);
+ }
+ }else
+
+ /* .session open DB NAME
+ ** Open a new session called NAME on the attached database DB.
+ ** DB is normally "main".
+ */
+ if( strcmp(azCmd[0],"open")==0 ){
+ char *zName;
+ if( nCmd!=3 ) goto session_syntax_error;
+ zName = azCmd[2];
+ if( zName[0]==0 ) goto session_syntax_error;
+ for(i=0; i<p->nSession; i++){
+ if( strcmp(p->aSession[i].zName,zName)==0 ){
+ utf8_printf(stderr, "Session \"%s\" already exists\n", zName);
+ goto meta_command_exit;
+ }
+ }
+ if( p->nSession>=ArraySize(p->aSession) ){
+ raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(p->aSession));
+ goto meta_command_exit;
+ }
+ pSession = &p->aSession[p->nSession];
+ rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
+ if( rc ){
+ raw_printf(stderr, "Cannot open session: error code=%d\n", rc);
+ rc = 0;
+ goto meta_command_exit;
+ }
+ pSession->nFilter = 0;
+ sqlite3session_table_filter(pSession->p, session_filter, pSession);
+ p->nSession++;
+ pSession->zName = sqlite3_mprintf("%s", zName);
+ }else
+ /* If no command name matches, show a syntax error */
+ session_syntax_error:
+ session_help(p);
+ }else
+#endif
+
+#ifdef SQLITE_DEBUG
+ /* Undocumented commands for internal testing. Subject to change
+ ** without notice. */
+ if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){
+ if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){
+ int i, v;
+ for(i=1; i<nArg; i++){
+ v = booleanValue(azArg[i]);
+ utf8_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
+ }
+ }
+ if( strncmp(azArg[0]+9, "integer", n-9)==0 ){
+ int i; sqlite3_int64 v;
+ for(i=1; i<nArg; i++){
+ char zBuf[200];
+ v = integerValue(azArg[i]);
+ sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
+ utf8_printf(p->out, "%s", zBuf);
+ }
+ }
+ }else
+#endif
+
+ if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){
+ int bIsInit = 0; /* True to initialize the SELFTEST table */
+ int bVerbose = 0; /* Verbose output */
+ int bSelftestExists; /* True if SELFTEST already exists */
+ int i, k; /* Loop counters */
+ int nTest = 0; /* Number of tests runs */
+ int nErr = 0; /* Number of errors seen */
+ ShellText str; /* Answer for a query */
+ sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
+
+ open_db(p,0);
+ for(i=1; i<nArg; i++){
+ const char *z = azArg[i];
+ if( z[0]=='-' && z[1]=='-' ) z++;
+ if( strcmp(z,"-init")==0 ){
+ bIsInit = 1;
+ }else
+ if( strcmp(z,"-v")==0 ){
+ bVerbose++;
+ }else
+ {
+ utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
+ azArg[i], azArg[0]);
+ raw_printf(stderr, "Should be one of: --init -v\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }
+ if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
+ != SQLITE_OK ){
+ bSelftestExists = 0;
+ }else{
+ bSelftestExists = 1;
+ }
+ if( bIsInit ){
+ createSelftestTable(p);
+ bSelftestExists = 1;
+ }
+ initText(&str);
+ appendText(&str, "x", 0);
+ for(k=bSelftestExists; k>=0; k--){
+ if( k==1 ){
+ rc = sqlite3_prepare_v2(p->db,
+ "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
+ -1, &pStmt, 0);
+ }else{
+ rc = sqlite3_prepare_v2(p->db,
+ "VALUES(0,'memo','Missing SELFTEST table - default checks only',''),"
+ " (1,'run','PRAGMA integrity_check','ok')",
+ -1, &pStmt, 0);
+ }
+ if( rc ){
+ raw_printf(stderr, "Error querying the selftest table\n");
+ rc = 1;
+ sqlite3_finalize(pStmt);
+ goto meta_command_exit;
+ }
+ for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){
+ int tno = sqlite3_column_int(pStmt, 0);
+ const char *zOp = (const char*)sqlite3_column_text(pStmt, 1);
+ const char *zSql = (const char*)sqlite3_column_text(pStmt, 2);
+ const char *zAns = (const char*)sqlite3_column_text(pStmt, 3);
+
+ k = 0;
+ if( bVerbose>0 ){
+ char *zQuote = sqlite3_mprintf("%q", zSql);
+ printf("%d: %s %s\n", tno, zOp, zSql);
+ sqlite3_free(zQuote);
+ }
+ if( strcmp(zOp,"memo")==0 ){
+ utf8_printf(p->out, "%s\n", zSql);
+ }else
+ if( strcmp(zOp,"run")==0 ){
+ char *zErrMsg = 0;
+ str.n = 0;
+ str.z[0] = 0;
+ rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
+ nTest++;
+ if( bVerbose ){
+ utf8_printf(p->out, "Result: %s\n", str.z);
+ }
+ if( rc || zErrMsg ){
+ nErr++;
+ rc = 1;
+ utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
+ sqlite3_free(zErrMsg);
+ }else if( strcmp(zAns,str.z)!=0 ){
+ nErr++;
+ rc = 1;
+ utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
+ utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
+ }
+ }else
+ {
+ utf8_printf(stderr,
+ "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
+ rc = 1;
+ break;
+ }
+ } /* End loop over rows of content from SELFTEST */
+ sqlite3_finalize(pStmt);
+ } /* End loop over k */
+ freeText(&str);
+ utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
+ }else
+
+ if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
+ if( nArg<2 || nArg>3 ){
+ raw_printf(stderr, "Usage: .separator COL ?ROW?\n");
+ rc = 1;
+ }
+ if( nArg>=2 ){
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
+ "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
+ }
+ if( nArg>=3 ){
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
+ "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
+ }
+ }else
+
+ if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){
+ const char *zLike = 0; /* Which table to checksum. 0 means everything */
+ int i; /* Loop counter */
+ int bSchema = 0; /* Also hash the schema */
+ int bSeparate = 0; /* Hash each table separately */
+ int iSize = 224; /* Hash algorithm to use */
+ int bDebug = 0; /* Only show the query that would have run */
+ sqlite3_stmt *pStmt; /* For querying tables names */
+ char *zSql; /* SQL to be run */
+ char *zSep; /* Separator */
+ ShellText sSql; /* Complete SQL for the query to run the hash */
+ ShellText sQuery; /* Set of queries used to read all content */
+ open_db(p, 0);
+ for(i=1; i<nArg; i++){
+ const char *z = azArg[i];
+ if( z[0]=='-' ){
+ z++;
+ if( z[0]=='-' ) z++;
+ if( strcmp(z,"schema")==0 ){
+ bSchema = 1;
+ }else
+ if( strcmp(z,"sha3-224")==0 || strcmp(z,"sha3-256")==0
+ || strcmp(z,"sha3-384")==0 || strcmp(z,"sha3-512")==0
+ ){
+ iSize = atoi(&z[5]);
+ }else
+ if( strcmp(z,"debug")==0 ){
+ bDebug = 1;
+ }else
+ {
+ utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
+ azArg[i], azArg[0]);
+ raw_printf(stderr, "Should be one of: --schema"
+ " --sha3-224 --sha3-255 --sha3-384 --sha3-512\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }else if( zLike ){
+ raw_printf(stderr, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }else{
+ zLike = z;
+ bSeparate = 1;
+ if( sqlite3_strlike("sqlite_%", zLike, 0)==0 ) bSchema = 1;
+ }
+ }
+ if( bSchema ){
+ zSql = "SELECT lower(name) FROM sqlite_master"
+ " WHERE type='table' AND coalesce(rootpage,0)>1"
+ " UNION ALL SELECT 'sqlite_master'"
+ " ORDER BY 1 collate nocase";
+ }else{
+ zSql = "SELECT lower(name) FROM sqlite_master"
+ " WHERE type='table' AND coalesce(rootpage,0)>1"
+ " AND name NOT LIKE 'sqlite_%'"
+ " ORDER BY 1 collate nocase";
+ }
+ sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ initText(&sQuery);
+ initText(&sSql);
+ appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0);
+ zSep = "VALUES(";
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ const char *zTab = (const char*)sqlite3_column_text(pStmt,0);
+ if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue;
+ if( strncmp(zTab, "sqlite_",7)!=0 ){
+ appendText(&sQuery,"SELECT * FROM ", 0);
+ appendText(&sQuery,zTab,'"');
+ appendText(&sQuery," NOT INDEXED;", 0);
+ }else if( strcmp(zTab, "sqlite_master")==0 ){
+ appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_master"
+ " ORDER BY name;", 0);
+ }else if( strcmp(zTab, "sqlite_sequence")==0 ){
+ appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence"
+ " ORDER BY name;", 0);
+ }else if( strcmp(zTab, "sqlite_stat1")==0 ){
+ appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1"
+ " ORDER BY tbl,idx;", 0);
+ }else if( strcmp(zTab, "sqlite_stat3")==0
+ || strcmp(zTab, "sqlite_stat4")==0 ){
+ appendText(&sQuery, "SELECT * FROM ", 0);
+ appendText(&sQuery, zTab, 0);
+ appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0);
+ }
+ appendText(&sSql, zSep, 0);
+ appendText(&sSql, sQuery.z, '\'');
+ sQuery.n = 0;
+ appendText(&sSql, ",", 0);
+ appendText(&sSql, zTab, '\'');
+ zSep = "),(";
+ }
+ sqlite3_finalize(pStmt);
+ if( bSeparate ){
+ zSql = sqlite3_mprintf(
+ "%s))"
+ " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label"
+ " FROM [sha3sum$query]",
+ sSql.z, iSize);
+ }else{
+ zSql = sqlite3_mprintf(
+ "%s))"
+ " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash"
+ " FROM [sha3sum$query]",
+ sSql.z, iSize);
+ }
+ freeText(&sQuery);
+ freeText(&sSql);
+ if( bDebug ){
+ utf8_printf(p->out, "%s\n", zSql);
+ }else{
+ shell_exec(p->db, zSql, shell_callback, p, 0);
+ }
+ sqlite3_free(zSql);
+ }else
+
+ if( c=='s'
+ && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
+ ){
+ char *zCmd;
+ int i, x;
+ if( nArg<2 ){
+ raw_printf(stderr, "Usage: .system COMMAND\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
+ for(i=2; i<nArg; i++){
+ zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
+ zCmd, azArg[i]);
+ }
+ x = system(zCmd);
+ sqlite3_free(zCmd);
+ if( x ) raw_printf(stderr, "System command returns %d\n", x);
+ }else
+
+ if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
+ static const char *azBool[] = { "off", "on", "full", "unk" };
+ int i;
+ if( nArg!=1 ){
+ raw_printf(stderr, "Usage: .show\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ utf8_printf(p->out, "%12.12s: %s\n","echo",
+ azBool[ShellHasFlag(p, SHFLG_Echo)]);
+ utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
+ utf8_printf(p->out, "%12.12s: %s\n","explain",
+ p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
+ utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
+ utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
+ utf8_printf(p->out, "%12.12s: ", "nullvalue");
+ output_c_string(p->out, p->nullValue);
+ raw_printf(p->out, "\n");
+ utf8_printf(p->out,"%12.12s: %s\n","output",
+ strlen30(p->outfile) ? p->outfile : "stdout");
+ utf8_printf(p->out,"%12.12s: ", "colseparator");
+ output_c_string(p->out, p->colSeparator);
+ raw_printf(p->out, "\n");
+ utf8_printf(p->out,"%12.12s: ", "rowseparator");
+ output_c_string(p->out, p->rowSeparator);
+ raw_printf(p->out, "\n");
+ utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]);
+ utf8_printf(p->out, "%12.12s: ", "width");
+ for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
+ raw_printf(p->out, "%d ", p->colWidth[i]);
+ }
+ raw_printf(p->out, "\n");
+ utf8_printf(p->out, "%12.12s: %s\n", "filename",
+ p->zDbFilename ? p->zDbFilename : "");
+ }else
+
+ if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
+ if( nArg==2 ){
+ p->statsOn = booleanValue(azArg[1]);
+ }else if( nArg==1 ){
+ display_stats(p->db, p, 0);
+ }else{
+ raw_printf(stderr, "Usage: .stats ?on|off?\n");
+ rc = 1;
+ }
+ }else
+
+ if( (c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0)
+ || (c=='i' && (strncmp(azArg[0], "indices", n)==0
+ || strncmp(azArg[0], "indexes", n)==0) )
+ ){
+ sqlite3_stmt *pStmt;
+ char **azResult;
+ int nRow, nAlloc;
+ int ii;
+ ShellText s;
+ initText(&s);
+ open_db(p, 0);
+ rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
+ if( rc ) return shellDatabaseError(p->db);
+
+ if( nArg>2 && c=='i' ){
+ /* It is an historical accident that the .indexes command shows an error
+ ** when called with the wrong number of arguments whereas the .tables
+ ** command does not. */
+ raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
+ const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
+ if( zDbName==0 ) continue;
+ if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0);
+ if( sqlite3_stricmp(zDbName, "main")==0 ){
+ appendText(&s, "SELECT name FROM ", 0);
+ }else{
+ appendText(&s, "SELECT ", 0);
+ appendText(&s, zDbName, '\'');
+ appendText(&s, "||'.'||name FROM ", 0);
+ }
+ appendText(&s, zDbName, '"');
+ appendText(&s, ".sqlite_master ", 0);
+ if( c=='t' ){
+ appendText(&s," WHERE type IN ('table','view')"
+ " AND name NOT LIKE 'sqlite_%'"
+ " AND name LIKE ?1", 0);
+ }else{
+ appendText(&s," WHERE type='index'"
+ " AND tbl_name LIKE ?1", 0);
+ }
+ }
+ rc = sqlite3_finalize(pStmt);
+ appendText(&s, " ORDER BY 1", 0);
+ rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);
+ freeText(&s);
+ if( rc ) return shellDatabaseError(p->db);
+
+ /* Run the SQL statement prepared by the above block. Store the results
+ ** as an array of nul-terminated strings in azResult[]. */
+ nRow = nAlloc = 0;
+ azResult = 0;
+ if( nArg>1 ){
+ sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
+ }
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ if( nRow>=nAlloc ){
+ char **azNew;
+ int n2 = nAlloc*2 + 10;
+ azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
+ if( azNew==0 ){
+ rc = shellNomemError();
+ break;
+ }
+ nAlloc = n2;
+ azResult = azNew;
+ }
+ azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
+ if( 0==azResult[nRow] ){
+ rc = shellNomemError();
+ break;
+ }
+ nRow++;
+ }
+ if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
+ rc = shellDatabaseError(p->db);
+ }
+
+ /* Pretty-print the contents of array azResult[] to the output */
+ if( rc==0 && nRow>0 ){
+ int len, maxlen = 0;
+ int i, j;
+ int nPrintCol, nPrintRow;
+ for(i=0; i<nRow; i++){
+ len = strlen30(azResult[i]);
+ if( len>maxlen ) maxlen = len;
+ }
+ nPrintCol = 80/(maxlen+2);
+ if( nPrintCol<1 ) nPrintCol = 1;
+ nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
+ for(i=0; i<nPrintRow; i++){
+ for(j=i; j<nRow; j+=nPrintRow){
+ char *zSp = j<nPrintRow ? "" : " ";
+ utf8_printf(p->out, "%s%-*s", zSp, maxlen,
+ azResult[j] ? azResult[j]:"");
+ }
+ raw_printf(p->out, "\n");
+ }
+ }
+
+ for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
+ sqlite3_free(azResult);
+ }else
+
+ /* Begin redirecting output to the file "testcase-out.txt" */
+ if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
+ output_reset(p);
+ p->out = output_file_open("testcase-out.txt");
+ if( p->out==0 ){
+ raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
+ }
+ if( nArg>=2 ){
+ sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
+ }else{
+ sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");
+ }
+ }else
+
+#ifndef SQLITE_UNTESTABLE
+ if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
+ static const struct {
+ const char *zCtrlName; /* Name of a test-control option */
+ int ctrlCode; /* Integer code for that option */
+ } aCtrl[] = {
+ { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE },
+ { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE },
+ { "prng_reset", SQLITE_TESTCTRL_PRNG_RESET },
+ { "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST },
+ { "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL },
+ { "benign_malloc_hooks", SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS },
+ { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE },
+ { "assert", SQLITE_TESTCTRL_ASSERT },
+ { "always", SQLITE_TESTCTRL_ALWAYS },
+ { "reserve", SQLITE_TESTCTRL_RESERVE },
+ { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
+ { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
+ { "byteorder", SQLITE_TESTCTRL_BYTEORDER },
+ { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
+ { "imposter", SQLITE_TESTCTRL_IMPOSTER },
+ };
+ int testctrl = -1;
+ int rc2 = 0;
+ int i, n2;
+ open_db(p, 0);
+
+ /* convert testctrl text option to value. allow any unique prefix
+ ** of the option name, or a numerical value. */
+ n2 = strlen30(azArg[1]);
+ for(i=0; i<ArraySize(aCtrl); i++){
+ if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
+ if( testctrl<0 ){
+ testctrl = aCtrl[i].ctrlCode;
+ }else{
+ utf8_printf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
+ testctrl = -1;
+ break;
+ }
+ }
+ }
+ if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]);
+ if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
+ utf8_printf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
+ }else{
+ switch(testctrl){
+
+ /* sqlite3_test_control(int, db, int) */
+ case SQLITE_TESTCTRL_OPTIMIZATIONS:
+ case SQLITE_TESTCTRL_RESERVE:
+ if( nArg==3 ){
+ int opt = (int)strtol(azArg[2], 0, 0);
+ rc2 = sqlite3_test_control(testctrl, p->db, opt);
+ raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
+ } else {
+ utf8_printf(stderr,"Error: testctrl %s takes a single int option\n",
+ azArg[1]);
+ }
+ break;
+
+ /* sqlite3_test_control(int) */
+ case SQLITE_TESTCTRL_PRNG_SAVE:
+ case SQLITE_TESTCTRL_PRNG_RESTORE:
+ case SQLITE_TESTCTRL_PRNG_RESET:
+ case SQLITE_TESTCTRL_BYTEORDER:
+ if( nArg==2 ){
+ rc2 = sqlite3_test_control(testctrl);
+ raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
+ } else {
+ utf8_printf(stderr,"Error: testctrl %s takes no options\n",
+ azArg[1]);
+ }
+ break;
+
+ /* sqlite3_test_control(int, uint) */
+ case SQLITE_TESTCTRL_PENDING_BYTE:
+ if( nArg==3 ){
+ unsigned int opt = (unsigned int)integerValue(azArg[2]);
+ rc2 = sqlite3_test_control(testctrl, opt);
+ raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
+ } else {
+ utf8_printf(stderr,"Error: testctrl %s takes a single unsigned"
+ " int option\n", azArg[1]);
+ }
+ break;
+
+ /* sqlite3_test_control(int, int) */
+ case SQLITE_TESTCTRL_ASSERT:
+ case SQLITE_TESTCTRL_ALWAYS:
+ case SQLITE_TESTCTRL_NEVER_CORRUPT:
+ if( nArg==3 ){
+ int opt = booleanValue(azArg[2]);
+ rc2 = sqlite3_test_control(testctrl, opt);
+ raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
+ } else {
+ utf8_printf(stderr,"Error: testctrl %s takes a single int option\n",
+ azArg[1]);
+ }
+ break;
+
+ /* sqlite3_test_control(int, char *) */
+#ifdef SQLITE_N_KEYWORD
+ case SQLITE_TESTCTRL_ISKEYWORD:
+ if( nArg==3 ){
+ const char *opt = azArg[2];
+ rc2 = sqlite3_test_control(testctrl, opt);
+ raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
+ } else {
+ utf8_printf(stderr,
+ "Error: testctrl %s takes a single char * option\n",
+ azArg[1]);
+ }
+ break;
+#endif
+
+ case SQLITE_TESTCTRL_IMPOSTER:
+ if( nArg==5 ){
+ rc2 = sqlite3_test_control(testctrl, p->db,
+ azArg[2],
+ integerValue(azArg[3]),
+ integerValue(azArg[4]));
+ raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
+ }else{
+ raw_printf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
+ }
+ break;
+
+ case SQLITE_TESTCTRL_BITVEC_TEST:
+ case SQLITE_TESTCTRL_FAULT_INSTALL:
+ case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
+ default:
+ utf8_printf(stderr,
+ "Error: CLI support for testctrl %s not implemented\n",
+ azArg[1]);
+ break;
+ }
+ }
+ }else
+#endif /* !defined(SQLITE_UNTESTABLE) */
+
+ if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){
+ open_db(p, 0);
+ sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
+ }else
+
+ if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){
+ if( nArg==2 ){
+ enableTimer = booleanValue(azArg[1]);
+ if( enableTimer && !HAS_TIMER ){
+ raw_printf(stderr, "Error: timer not available on this system.\n");
+ enableTimer = 0;
+ }
+ }else{
+ raw_printf(stderr, "Usage: .timer on|off\n");
+ rc = 1;
+ }
+ }else
+
+ if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
+ open_db(p, 0);
+ if( nArg!=2 ){
+ raw_printf(stderr, "Usage: .trace FILE|off\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ output_file_close(p->traceOut);
+ p->traceOut = output_file_open(azArg[1]);
+#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
+ if( p->traceOut==0 ){
+ sqlite3_trace_v2(p->db, 0, 0, 0);
+ }else{
+ sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut);
+ }
+#endif
+ }else
+
+#if SQLITE_USER_AUTHENTICATION
+ if( c=='u' && strncmp(azArg[0], "user", n)==0 ){
+ if( nArg<2 ){
+ raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ open_db(p, 0);
+ if( strcmp(azArg[1],"login")==0 ){
+ if( nArg!=4 ){
+ raw_printf(stderr, "Usage: .user login USER PASSWORD\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
+ (int)strlen(azArg[3]));
+ if( rc ){
+ utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
+ rc = 1;
+ }
+ }else if( strcmp(azArg[1],"add")==0 ){
+ if( nArg!=5 ){
+ raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ rc = sqlite3_user_add(p->db, azArg[2],
+ azArg[3], (int)strlen(azArg[3]),
+ booleanValue(azArg[4]));
+ if( rc ){
+ raw_printf(stderr, "User-Add failed: %d\n", rc);
+ rc = 1;
+ }
+ }else if( strcmp(azArg[1],"edit")==0 ){
+ if( nArg!=5 ){
+ raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ rc = sqlite3_user_change(p->db, azArg[2],
+ azArg[3], (int)strlen(azArg[3]),
+ booleanValue(azArg[4]));
+ if( rc ){
+ raw_printf(stderr, "User-Edit failed: %d\n", rc);
+ rc = 1;
+ }
+ }else if( strcmp(azArg[1],"delete")==0 ){
+ if( nArg!=3 ){
+ raw_printf(stderr, "Usage: .user delete USER\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ rc = sqlite3_user_delete(p->db, azArg[2]);
+ if( rc ){
+ raw_printf(stderr, "User-Delete failed: %d\n", rc);
+ rc = 1;
+ }
+ }else{
+ raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }else
+#endif /* SQLITE_USER_AUTHENTICATION */
+
+ if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
+ utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
+ sqlite3_libversion(), sqlite3_sourceid());
+ }else
+
+ if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){
+ const char *zDbName = nArg==2 ? azArg[1] : "main";
+ sqlite3_vfs *pVfs = 0;
+ if( p->db ){
+ sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
+ if( pVfs ){
+ utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
+ raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
+ raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
+ raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
+ }
+ }
+ }else
+
+ if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){
+ sqlite3_vfs *pVfs;
+ sqlite3_vfs *pCurrent = 0;
+ if( p->db ){
+ sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
+ }
+ for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
+ utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
+ pVfs==pCurrent ? " <--- CURRENT" : "");
+ raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
+ raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
+ raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
+ if( pVfs->pNext ){
+ raw_printf(p->out, "-----------------------------------\n");
+ }
+ }
+ }else
+
+ if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
+ const char *zDbName = nArg==2 ? azArg[1] : "main";
+ char *zVfsName = 0;
+ if( p->db ){
+ sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
+ if( zVfsName ){
+ utf8_printf(p->out, "%s\n", zVfsName);
+ sqlite3_free(zVfsName);
+ }
+ }
+ }else
+
+#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
+ if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
+ sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
+ }else
+#endif
+
+ if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
+ int j;
+ assert( nArg<=ArraySize(azArg) );
+ for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
+ p->colWidth[j-1] = (int)integerValue(azArg[j]);
+ }
+ }else
+
+ {
+ utf8_printf(stderr, "Error: unknown command or invalid arguments: "
+ " \"%s\". Enter \".help\" for help\n", azArg[0]);
+ rc = 1;
+ }
+
+meta_command_exit:
+ if( p->outCount ){
+ p->outCount--;
+ if( p->outCount==0 ) output_reset(p);
+ }
+ return rc;
+}
+
+/*
+** Return TRUE if a semicolon occurs anywhere in the first N characters
+** of string z[].
+*/
+static int line_contains_semicolon(const char *z, int N){
+ int i;
+ for(i=0; i<N; i++){ if( z[i]==';' ) return 1; }
+ return 0;
+}
+
+/*
+** Test to see if a line consists entirely of whitespace.
+*/
+static int _all_whitespace(const char *z){
+ for(; *z; z++){
+ if( IsSpace(z[0]) ) continue;
+ if( *z=='/' && z[1]=='*' ){
+ z += 2;
+ while( *z && (*z!='*' || z[1]!='/') ){ z++; }
+ if( *z==0 ) return 0;
+ z++;
+ continue;
+ }
+ if( *z=='-' && z[1]=='-' ){
+ z += 2;
+ while( *z && *z!='\n' ){ z++; }
+ if( *z==0 ) return 1;
+ continue;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+/*
+** Return TRUE if the line typed in is an SQL command terminator other
+** than a semi-colon. The SQL Server style "go" command is understood
+** as is the Oracle "/".
+*/
+static int line_is_command_terminator(const char *zLine){
+ while( IsSpace(zLine[0]) ){ zLine++; };
+ if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
+ return 1; /* Oracle */
+ }
+ if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o'
+ && _all_whitespace(&zLine[2]) ){
+ return 1; /* SQL Server */
+ }
+ return 0;
+}
+
+/*
+** Return true if zSql is a complete SQL statement. Return false if it
+** ends in the middle of a string literal or C-style comment.
+*/
+static int line_is_complete(char *zSql, int nSql){
+ int rc;
+ if( zSql==0 ) return 1;
+ zSql[nSql] = ';';
+ zSql[nSql+1] = 0;
+ rc = sqlite3_complete(zSql);
+ zSql[nSql] = 0;
+ return rc;
+}
+
+/*
+** Run a single line of SQL
+*/
+static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
+ int rc;
+ char *zErrMsg = 0;
+
+ open_db(p, 0);
+ if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql);
+ BEGIN_TIMER;
+ rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
+ END_TIMER;
+ if( rc || zErrMsg ){
+ char zPrefix[100];
+ if( in!=0 || !stdin_is_interactive ){
+ sqlite3_snprintf(sizeof(zPrefix), zPrefix,
+ "Error: near line %d:", startline);
+ }else{
+ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
+ }
+ if( zErrMsg!=0 ){
+ utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg);
+ sqlite3_free(zErrMsg);
+ zErrMsg = 0;
+ }else{
+ utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
+ }
+ return 1;
+ }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
+ raw_printf(p->out, "changes: %3d total_changes: %d\n",
+ sqlite3_changes(p->db), sqlite3_total_changes(p->db));
+ }
+ return 0;
+}
+
+
+/*
+** Read input from *in and process it. If *in==0 then input
+** is interactive - the user is typing it it. Otherwise, input
+** is coming from a file or device. A prompt is issued and history
+** is saved only if input is interactive. An interrupt signal will
+** cause this routine to exit immediately, unless input is interactive.
+**
+** Return the number of errors.
+*/
+static int process_input(ShellState *p, FILE *in){
+ char *zLine = 0; /* A single input line */
+ char *zSql = 0; /* Accumulated SQL text */
+ int nLine; /* Length of current line */
+ int nSql = 0; /* Bytes of zSql[] used */
+ int nAlloc = 0; /* Allocated zSql[] space */
+ int nSqlPrior = 0; /* Bytes of zSql[] used by prior line */
+ int rc; /* Error code */
+ int errCnt = 0; /* Number of errors seen */
+ int lineno = 0; /* Current line number */
+ int startline = 0; /* Line number for start of current input */
+
+ while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
+ fflush(p->out);
+ zLine = one_input_line(in, zLine, nSql>0);
+ if( zLine==0 ){
+ /* End of input */
+ if( in==0 && stdin_is_interactive ) printf("\n");
+ break;
+ }
+ if( seenInterrupt ){
+ if( in!=0 ) break;
+ seenInterrupt = 0;
+ }
+ lineno++;
+ if( nSql==0 && _all_whitespace(zLine) ){
+ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
+ continue;
+ }
+ if( zLine && zLine[0]=='.' && nSql==0 ){
+ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
+ rc = do_meta_command(zLine, p);
+ if( rc==2 ){ /* exit requested */
+ break;
+ }else if( rc ){
+ errCnt++;
+ }
+ continue;
+ }
+ if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){
+ memcpy(zLine,";",2);
+ }
+ nLine = strlen30(zLine);
+ if( nSql+nLine+2>=nAlloc ){
+ nAlloc = nSql+nLine+100;
+ zSql = realloc(zSql, nAlloc);
+ if( zSql==0 ){
+ raw_printf(stderr, "Error: out of memory\n");
+ exit(1);
+ }
+ }
+ nSqlPrior = nSql;
+ if( nSql==0 ){
+ int i;
+ for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
+ assert( nAlloc>0 && zSql!=0 );
+ memcpy(zSql, zLine+i, nLine+1-i);
+ startline = lineno;
+ nSql = nLine-i;
+ }else{
+ zSql[nSql++] = '\n';
+ memcpy(zSql+nSql, zLine, nLine+1);
+ nSql += nLine;
+ }
+ if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
+ && sqlite3_complete(zSql) ){
+ errCnt += runOneSqlLine(p, zSql, in, startline);
+ nSql = 0;
+ if( p->outCount ){
+ output_reset(p);
+ p->outCount = 0;
+ }
+ }else if( nSql && _all_whitespace(zSql) ){
+ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
+ nSql = 0;
+ }
+ }
+ if( nSql && !_all_whitespace(zSql) ){
+ runOneSqlLine(p, zSql, in, startline);
+ }
+ free(zSql);
+ free(zLine);
+ return errCnt>0;
+}
+
+/*
+** Return a pathname which is the user's home directory. A
+** 0 return indicates an error of some kind.
+*/
+static char *find_home_dir(int clearFlag){
+ static char *home_dir = NULL;
+ if( clearFlag ){
+ free(home_dir);
+ home_dir = 0;
+ return 0;
+ }
+ if( home_dir ) return home_dir;
+
+#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
+ && !defined(__RTP__) && !defined(_WRS_KERNEL)
+ {
+ struct passwd *pwent;
+ uid_t uid = getuid();
+ if( (pwent=getpwuid(uid)) != NULL) {
+ home_dir = pwent->pw_dir;
+ }
+ }
+#endif
+
+#if defined(_WIN32_WCE)
+ /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
+ */
+ home_dir = "/";
+#else
+
+#if defined(_WIN32) || defined(WIN32)
+ if (!home_dir) {
+ home_dir = getenv("USERPROFILE");
+ }
+#endif
+
+ if (!home_dir) {
+ home_dir = getenv("HOME");
+ }
+
+#if defined(_WIN32) || defined(WIN32)
+ if (!home_dir) {
+ char *zDrive, *zPath;
+ int n;
+ zDrive = getenv("HOMEDRIVE");
+ zPath = getenv("HOMEPATH");
+ if( zDrive && zPath ){
+ n = strlen30(zDrive) + strlen30(zPath) + 1;
+ home_dir = malloc( n );
+ if( home_dir==0 ) return 0;
+ sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
+ return home_dir;
+ }
+ home_dir = "c:\\";
+ }
+#endif
+
+#endif /* !_WIN32_WCE */
+
+ if( home_dir ){
+ int n = strlen30(home_dir) + 1;
+ char *z = malloc( n );
+ if( z ) memcpy(z, home_dir, n);
+ home_dir = z;
+ }
+
+ return home_dir;
+}
+
+/*
+** Read input from the file given by sqliterc_override. Or if that
+** parameter is NULL, take input from ~/.sqliterc
+**
+** Returns the number of errors.
+*/
+static void process_sqliterc(
+ ShellState *p, /* Configuration data */
+ const char *sqliterc_override /* Name of config file. NULL to use default */
+){
+ char *home_dir = NULL;
+ const char *sqliterc = sqliterc_override;
+ char *zBuf = 0;
+ FILE *in = NULL;
+
+ if (sqliterc == NULL) {
+ home_dir = find_home_dir(0);
+ if( home_dir==0 ){
+ raw_printf(stderr, "-- warning: cannot find home directory;"
+ " cannot read ~/.sqliterc\n");
+ return;
+ }
+ sqlite3_initialize();
+ zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
+ sqliterc = zBuf;
+ }
+ in = fopen(sqliterc,"rb");
+ if( in ){
+ if( stdin_is_interactive ){
+ utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
+ }
+ process_input(p,in);
+ fclose(in);
+ }
+ sqlite3_free(zBuf);
+}
+
+/*
+** Show available command line options
+*/
+static const char zOptions[] =
+ " -ascii set output mode to 'ascii'\n"
+ " -bail stop after hitting an error\n"
+ " -batch force batch I/O\n"
+ " -column set output mode to 'column'\n"
+ " -cmd COMMAND run \"COMMAND\" before reading stdin\n"
+ " -csv set output mode to 'csv'\n"
+ " -echo print commands before execution\n"
+ " -init FILENAME read/process named file\n"
+ " -[no]header turn headers on or off\n"
+#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
+ " -heap SIZE Size of heap for memsys3 or memsys5\n"
+#endif
+ " -help show this message\n"
+ " -html set output mode to HTML\n"
+ " -interactive force interactive I/O\n"
+ " -line set output mode to 'line'\n"
+ " -list set output mode to 'list'\n"
+ " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
+ " -mmap N default mmap size set to N\n"
+#ifdef SQLITE_ENABLE_MULTIPLEX
+ " -multiplex enable the multiplexor VFS\n"
+#endif
+ " -newline SEP set output row separator. Default: '\\n'\n"
+ " -nullvalue TEXT set text string for NULL values. Default ''\n"
+ " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
+ " -quote set output mode to 'quote'\n"
+ " -separator SEP set output column separator. Default: '|'\n"
+ " -stats print memory stats before each finalize\n"
+ " -version show SQLite version\n"
+ " -vfs NAME use NAME as the default VFS\n"
+#ifdef SQLITE_ENABLE_VFSTRACE
+ " -vfstrace enable tracing of all VFS calls\n"
+#endif
+;
+static void usage(int showDetail){
+ utf8_printf(stderr,
+ "Usage: %s [OPTIONS] FILENAME [SQL]\n"
+ "FILENAME is the name of an SQLite database. A new database is created\n"
+ "if the file does not previously exist.\n", Argv0);
+ if( showDetail ){
+ utf8_printf(stderr, "OPTIONS include:\n%s", zOptions);
+ }else{
+ raw_printf(stderr, "Use the -help option for additional information\n");
+ }
+ exit(1);
+}
+
+/*
+** Initialize the state information in data
+*/
+static void main_init(ShellState *data) {
+ memset(data, 0, sizeof(*data));
+ data->normalMode = data->cMode = data->mode = MODE_List;
+ data->autoExplain = 1;
+ memcpy(data->colSeparator,SEP_Column, 2);
+ memcpy(data->rowSeparator,SEP_Row, 2);
+ data->showHeader = 0;
+ data->shellFlgs = SHFLG_Lookaside;
+ sqlite3_config(SQLITE_CONFIG_URI, 1);
+ sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
+ sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
+ sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
+ sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
+}
+
+/*
+** Output text to the console in a font that attracts extra attention.
+*/
+#ifdef _WIN32
+static void printBold(const char *zText){
+ HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
+ GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
+ SetConsoleTextAttribute(out,
+ FOREGROUND_RED|FOREGROUND_INTENSITY
+ );
+ printf("%s", zText);
+ SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
+}
+#else
+static void printBold(const char *zText){
+ printf("\033[1m%s\033[0m", zText);
+}
+#endif
+
+/*
+** Get the argument to an --option. Throw an error and die if no argument
+** is available.
+*/
+static char *cmdline_option_value(int argc, char **argv, int i){
+ if( i==argc ){
+ utf8_printf(stderr, "%s: Error: missing argument to %s\n",
+ argv[0], argv[argc-1]);
+ exit(1);
+ }
+ return argv[i];
+}
+
+#ifndef SQLITE_SHELL_IS_UTF8
+# if (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
+# define SQLITE_SHELL_IS_UTF8 (0)
+# else
+# define SQLITE_SHELL_IS_UTF8 (1)
+# endif
+#endif
+
+#if SQLITE_SHELL_IS_UTF8
+int SQLITE_CDECL main(int argc, char **argv){
+#else
+int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
+ char **argv;
+#endif
+ char *zErrMsg = 0;
+ ShellState data;
+ const char *zInitFile = 0;
+ int i;
+ int rc = 0;
+ int warnInmemoryDb = 0;
+ int readStdin = 1;
+ int nCmd = 0;
+ char **azCmd = 0;
+
+ setBinaryMode(stdin, 0);
+ setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
+ stdin_is_interactive = isatty(0);
+ stdout_is_console = isatty(1);
+
+#if USE_SYSTEM_SQLITE+0!=1
+ if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
+ utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
+ sqlite3_sourceid(), SQLITE_SOURCE_ID);
+ exit(1);
+ }
+#endif
+ main_init(&data);
+#if !SQLITE_SHELL_IS_UTF8
+ sqlite3_initialize();
+ argv = sqlite3_malloc64(sizeof(argv[0])*argc);
+ if( argv==0 ){
+ raw_printf(stderr, "out of memory\n");
+ exit(1);
+ }
+ for(i=0; i<argc; i++){
+ argv[i] = sqlite3_win32_unicode_to_utf8(wargv[i]);
+ if( argv[i]==0 ){
+ raw_printf(stderr, "out of memory\n");
+ exit(1);
+ }
+ }
+#endif
+ assert( argc>=1 && argv && argv[0] );
+ Argv0 = argv[0];
+
+ /* Make sure we have a valid signal handler early, before anything
+ ** else is done.
+ */
+#ifdef SIGINT
+ signal(SIGINT, interrupt_handler);
+#endif
+
+#ifdef SQLITE_SHELL_DBNAME_PROC
+ {
+ /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
+ ** of a C-function that will provide the name of the database file. Use
+ ** this compile-time option to embed this shell program in larger
+ ** applications. */
+ extern void SQLITE_SHELL_DBNAME_PROC(const char**);
+ SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename);
+ warnInmemoryDb = 0;
+ }
+#endif
+
+ /* Begin evanm patch. */
+#if !defined(__APPLE__)
+ extern int sqlite_shell_init_icu();
+ if( !sqlite_shell_init_icu() ){
+ fprintf(stderr, "%s: warning: couldn't find icudt38.dll; "
+ "queries against ICU FTS tables will fail.\n", argv[0]);
+ }
+#endif /* !defined(__APPLE__) */
+ /* End evanm patch. */
+
+ /* Do an initial pass through the command-line argument to locate
+ ** the name of the database file, the name of the initialization file,
+ ** the size of the alternative malloc heap,
+ ** and the first command to execute.
+ */
+ for(i=1; i<argc; i++){
+ char *z;
+ z = argv[i];
+ if( z[0]!='-' ){
+ if( data.zDbFilename==0 ){
+ data.zDbFilename = z;
+ }else{
+ /* Excesss arguments are interpreted as SQL (or dot-commands) and
+ ** mean that nothing is read from stdin */
+ readStdin = 0;
+ nCmd++;
+ azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
+ if( azCmd==0 ){
+ raw_printf(stderr, "out of memory\n");
+ exit(1);
+ }
+ azCmd[nCmd-1] = z;
+ }
+ }
+ if( z[1]=='-' ) z++;
+ if( strcmp(z,"-separator")==0
+ || strcmp(z,"-nullvalue")==0
+ || strcmp(z,"-newline")==0
+ || strcmp(z,"-cmd")==0
+ ){
+ (void)cmdline_option_value(argc, argv, ++i);
+ }else if( strcmp(z,"-init")==0 ){
+ zInitFile = cmdline_option_value(argc, argv, ++i);
+ }else if( strcmp(z,"-batch")==0 ){
+ /* Need to check for batch mode here to so we can avoid printing
+ ** informational messages (like from process_sqliterc) before
+ ** we do the actual processing of arguments later in a second pass.
+ */
+ stdin_is_interactive = 0;
+ }else if( strcmp(z,"-heap")==0 ){
+#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
+ const char *zSize;
+ sqlite3_int64 szHeap;
+
+ zSize = cmdline_option_value(argc, argv, ++i);
+ szHeap = integerValue(zSize);
+ if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
+ sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
+#else
+ (void)cmdline_option_value(argc, argv, ++i);
+#endif
+ }else if( strcmp(z,"-pagecache")==0 ){
+ int n, sz;
+ sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
+ if( sz>70000 ) sz = 70000;
+ if( sz<0 ) sz = 0;
+ n = (int)integerValue(cmdline_option_value(argc,argv,++i));
+ sqlite3_config(SQLITE_CONFIG_PAGECACHE,
+ (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
+ data.shellFlgs |= SHFLG_Pagecache;
+ }else if( strcmp(z,"-lookaside")==0 ){
+ int n, sz;
+ sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
+ if( sz<0 ) sz = 0;
+ n = (int)integerValue(cmdline_option_value(argc,argv,++i));
+ if( n<0 ) n = 0;
+ sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n);
+ if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;
+#ifdef SQLITE_ENABLE_VFSTRACE
+ }else if( strcmp(z,"-vfstrace")==0 ){
+ extern int vfstrace_register(
+ const char *zTraceName,
+ const char *zOldVfsName,
+ int (*xOut)(const char*,void*),
+ void *pOutArg,
+ int makeDefault
+ );
+ vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
+#endif
+#ifdef SQLITE_ENABLE_MULTIPLEX
+ }else if( strcmp(z,"-multiplex")==0 ){
+ extern int sqlite3_multiple_initialize(const char*,int);
+ sqlite3_multiplex_initialize(0, 1);
+#endif
+ }else if( strcmp(z,"-mmap")==0 ){
+ sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
+ sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
+ }else if( strcmp(z,"-vfs")==0 ){
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i));
+ if( pVfs ){
+ sqlite3_vfs_register(pVfs, 1);
+ }else{
+ utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]);
+ exit(1);
+ }
+ }
+ }
+ if( data.zDbFilename==0 ){
+#ifndef SQLITE_OMIT_MEMORYDB
+ data.zDbFilename = ":memory:";
+ warnInmemoryDb = argc==1;
+#else
+ utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
+ return 1;
+#endif
+ }
+ data.out = stdout;
+
+ /* Go ahead and open the database file if it already exists. If the
+ ** file does not exist, delay opening it. This prevents empty database
+ ** files from being created if a user mistypes the database name argument
+ ** to the sqlite command-line tool.
+ */
+ if( access(data.zDbFilename, 0)==0 ){
+ open_db(&data, 0);
+ }
+
+ /* Process the initialization file if there is one. If no -init option
+ ** is given on the command line, look for a file named ~/.sqliterc and
+ ** try to process it.
+ */
+ process_sqliterc(&data,zInitFile);
+
+ /* Make a second pass through the command-line argument and set
+ ** options. This second pass is delayed until after the initialization
+ ** file is processed so that the command-line arguments will override
+ ** settings in the initialization file.
+ */
+ for(i=1; i<argc; i++){
+ char *z = argv[i];
+ if( z[0]!='-' ) continue;
+ if( z[1]=='-' ){ z++; }
+ if( strcmp(z,"-init")==0 ){
+ i++;
+ }else if( strcmp(z,"-html")==0 ){
+ data.mode = MODE_Html;
+ }else if( strcmp(z,"-list")==0 ){
+ data.mode = MODE_List;
+ }else if( strcmp(z,"-quote")==0 ){
+ data.mode = MODE_Quote;
+ }else if( strcmp(z,"-line")==0 ){
+ data.mode = MODE_Line;
+ }else if( strcmp(z,"-column")==0 ){
+ data.mode = MODE_Column;
+ }else if( strcmp(z,"-csv")==0 ){
+ data.mode = MODE_Csv;
+ memcpy(data.colSeparator,",",2);
+ }else if( strcmp(z,"-ascii")==0 ){
+ data.mode = MODE_Ascii;
+ sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
+ SEP_Unit);
+ sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
+ SEP_Record);
+ }else if( strcmp(z,"-separator")==0 ){
+ sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
+ "%s",cmdline_option_value(argc,argv,++i));
+ }else if( strcmp(z,"-newline")==0 ){
+ sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
+ "%s",cmdline_option_value(argc,argv,++i));
+ }else if( strcmp(z,"-nullvalue")==0 ){
+ sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
+ "%s",cmdline_option_value(argc,argv,++i));
+ }else if( strcmp(z,"-header")==0 ){
+ data.showHeader = 1;
+ }else if( strcmp(z,"-noheader")==0 ){
+ data.showHeader = 0;
+ }else if( strcmp(z,"-echo")==0 ){
+ ShellSetFlag(&data, SHFLG_Echo);
+ }else if( strcmp(z,"-eqp")==0 ){
+ data.autoEQP = 1;
+ }else if( strcmp(z,"-eqpfull")==0 ){
+ data.autoEQP = 2;
+ }else if( strcmp(z,"-stats")==0 ){
+ data.statsOn = 1;
+ }else if( strcmp(z,"-scanstats")==0 ){
+ data.scanstatsOn = 1;
+ }else if( strcmp(z,"-backslash")==0 ){
+ /* Undocumented command-line option: -backslash
+ ** Causes C-style backslash escapes to be evaluated in SQL statements
+ ** prior to sending the SQL into SQLite. Useful for injecting
+ ** crazy bytes in the middle of SQL statements for testing and debugging.
+ */
+ ShellSetFlag(&data, SHFLG_Backslash);
+ }else if( strcmp(z,"-bail")==0 ){
+ bail_on_error = 1;
+ }else if( strcmp(z,"-version")==0 ){
+ printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
+ return 0;
+ }else if( strcmp(z,"-interactive")==0 ){
+ stdin_is_interactive = 1;
+ }else if( strcmp(z,"-batch")==0 ){
+ stdin_is_interactive = 0;
+ }else if( strcmp(z,"-heap")==0 ){
+ i++;
+ }else if( strcmp(z,"-pagecache")==0 ){
+ i+=2;
+ }else if( strcmp(z,"-lookaside")==0 ){
+ i+=2;
+ }else if( strcmp(z,"-mmap")==0 ){
+ i++;
+ }else if( strcmp(z,"-vfs")==0 ){
+ i++;
+#ifdef SQLITE_ENABLE_VFSTRACE
+ }else if( strcmp(z,"-vfstrace")==0 ){
+ i++;
+#endif
+#ifdef SQLITE_ENABLE_MULTIPLEX
+ }else if( strcmp(z,"-multiplex")==0 ){
+ i++;
+#endif
+ }else if( strcmp(z,"-help")==0 ){
+ usage(1);
+ }else if( strcmp(z,"-cmd")==0 ){
+ /* Run commands that follow -cmd first and separately from commands
+ ** that simply appear on the command-line. This seems goofy. It would
+ ** be better if all commands ran in the order that they appear. But
+ ** we retain the goofy behavior for historical compatibility. */
+ if( i==argc-1 ) break;
+ z = cmdline_option_value(argc,argv,++i);
+ if( z[0]=='.' ){
+ rc = do_meta_command(z, &data);
+ if( rc && bail_on_error ) return rc==2 ? 0 : rc;
+ }else{
+ open_db(&data, 0);
+ rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
+ if( zErrMsg!=0 ){
+ utf8_printf(stderr,"Error: %s\n", zErrMsg);
+ if( bail_on_error ) return rc!=0 ? rc : 1;
+ }else if( rc!=0 ){
+ utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z);
+ if( bail_on_error ) return rc;
+ }
+ }
+ }else{
+ utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
+ raw_printf(stderr,"Use -help for a list of options.\n");
+ return 1;
+ }
+ data.cMode = data.mode;
+ }
+
+ if( !readStdin ){
+ /* Run all arguments that do not begin with '-' as if they were separate
+ ** command-line inputs, except for the argToSkip argument which contains
+ ** the database filename.
+ */
+ for(i=0; i<nCmd; i++){
+ if( azCmd[i][0]=='.' ){
+ rc = do_meta_command(azCmd[i], &data);
+ if( rc ) return rc==2 ? 0 : rc;
+ }else{
+ open_db(&data, 0);
+ rc = shell_exec(data.db, azCmd[i], shell_callback, &data, &zErrMsg);
+ if( zErrMsg!=0 ){
+ utf8_printf(stderr,"Error: %s\n", zErrMsg);
+ return rc!=0 ? rc : 1;
+ }else if( rc!=0 ){
+ utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
+ return rc;
+ }
+ }
+ }
+ free(azCmd);
+ }else{
+ /* Run commands received from standard input
+ */
+ if( stdin_is_interactive ){
+ char *zHome;
+ char *zHistory = 0;
+ int nHistory;
+ printf(
+ "SQLite version %s %.19s\n" /*extra-version-info*/
+ "Enter \".help\" for usage hints.\n",
+ sqlite3_libversion(), sqlite3_sourceid()
+ );
+ if( warnInmemoryDb ){
+ printf("Connected to a ");
+ printBold("transient in-memory database");
+ printf(".\nUse \".open FILENAME\" to reopen on a "
+ "persistent database.\n");
+ }
+ zHome = find_home_dir(0);
+ if( zHome ){
+ nHistory = strlen30(zHome) + 20;
+ if( (zHistory = malloc(nHistory))!=0 ){
+ sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
+ }
+ }
+ if( zHistory ){ shell_read_history(zHistory); }
+#if HAVE_READLINE || HAVE_EDITLINE
+ rl_attempted_completion_function = readline_completion;
+#elif HAVE_LINENOISE
+ linenoiseSetCompletionCallback(linenoise_completion);
+#endif
+ rc = process_input(&data, 0);
+ if( zHistory ){
+ shell_stifle_history(2000);
+ shell_write_history(zHistory);
+ free(zHistory);
+ }
+ }else{
+ rc = process_input(&data, stdin);
+ }
+ }
+ set_table_name(&data, 0);
+ if( data.db ){
+ session_close_all(&data);
+ sqlite3_close(data.db);
+ }
+ sqlite3_free(data.zFreeOnClose);
+ find_home_dir(1);
+#if !SQLITE_SHELL_IS_UTF8
+ for(i=0; i<argc; i++) sqlite3_free(argv[i]);
+ sqlite3_free(argv);
+#endif
+ return rc;
+}
+
diff --git a/third_party/sqlite/amalgamation/sqlite3.c b/third_party/sqlite/amalgamation/sqlite3.c
index ab5a00d..7230430 100644
--- a/third_party/sqlite/amalgamation/sqlite3.c
+++ b/third_party/sqlite/amalgamation/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.20.0. By combining all the individual C code files into this
+** version 3.21.0. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -209,6 +209,9 @@ static const char * const sqlite3azCompileOpt[] = {
#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",
#endif
@@ -828,17 +831,6 @@ SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){
#endif
/*
-** Make sure that rand_s() is available on Windows systems with MSVC 2005
-** or higher.
-*/
-#if defined(_MSC_VER) && _MSC_VER>=1400
-/* TODO(shess): Already defined by build/config/win/BUILD.gn */
-#ifndef _CRT_RAND_S
-# define _CRT_RAND_S
-#endif
-#endif
-
-/*
** Include the header file used to customize the compiler options for MSVC.
** This should be done first so that it can successfully prevent spurious
** compiler warnings due to subsequent content in this file and other files
@@ -1147,15 +1139,17 @@ extern "C" {
** a string which identifies a particular check-in of SQLite
** within its configuration management system. ^The SQLITE_SOURCE_ID
** string contains the date and time of the check-in (UTC) and a SHA1
-** or SHA3-256 hash of the entire source tree.
+** or SHA3-256 hash of the entire source tree. If the source code has
+** been edited in any way since it was last checked in, then the last
+** four hexadecimal digits of the hash may be modified.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.20.0"
-#define SQLITE_VERSION_NUMBER 3020000
-#define SQLITE_SOURCE_ID "2017-07-19 19:48:40 0a5e1c04d9d07bb7fd6546a9ddac1bf42b19ea19c2b79570aea6cd4226887a27"
+#define SQLITE_VERSION "3.21.0"
+#define SQLITE_VERSION_NUMBER 3021000
+#define SQLITE_SOURCE_ID "2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de4alt1"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -1171,7 +1165,7 @@ extern "C" {
**
** <blockquote><pre>
** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
-** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
+** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
** </pre></blockquote>)^
**
@@ -1181,9 +1175,11 @@ 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
+** [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.
+** [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].)^
**
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
@@ -1464,7 +1460,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
-#define SQLITE_EMPTY 16 /* Not used */
+#define SQLITE_EMPTY 16 /* Internal use only */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
@@ -1526,6 +1522,9 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
+#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_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
@@ -1612,6 +1611,11 @@ SQLITE_API int sqlite3_exec(
** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on
** read-only media and cannot be changed even by processes with
** elevated privileges.
+**
+** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
+** filesystem supports doing multiple write operations atomically when those
+** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
+** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -1627,6 +1631,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
+#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
/*
** CAPI3REF: File Locking Levels
@@ -1761,6 +1766,7 @@ struct sqlite3_file {
** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
** <li> [SQLITE_IOCAP_IMMUTABLE]
+** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
** </ul>
**
** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -2044,6 +2050,40 @@ struct sqlite3_io_methods {
** 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.
+**
+** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
+** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
+** the file descriptor is placed in "batch write mode", which
+** means all subsequent write operations will be deferred and done
+** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems
+** that do not support batch atomic writes will return SQLITE_NOTFOUND.
+** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
+** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
+** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
+** no VFS interface calls on the same [sqlite3_file] file descriptor
+** except for calls to the xWrite method and the xFileControl method
+** with [SQLITE_FCNTL_SIZE_HINT].
+**
+** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
+** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
+** 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.
+** ^Regardless of whether or not it is successful, this file control takes
+** the file descriptor out of batch write mode so that all subsequent
+** write operations are independent.
+** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
+** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
+**
+** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
+** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
+** 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.
+** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
+** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -2075,6 +2115,9 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_JOURNAL_POINTER 28
#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
#define SQLITE_FCNTL_PDB 30
+#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31
+#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32
+#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -2645,6 +2688,16 @@ struct sqlite3_mem_methods {
** routines with a wrapper that simulations memory allocation failure or
** tracks memory usage, for example. </dd>
**
+** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt>
+** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of
+** type int, interpreted as a boolean, which if true provides a hint to
+** SQLite that it should avoid large memory allocations if possible.
+** SQLite will run faster if it is free to make large memory allocations,
+** but some application might prefer to run slower in exchange for
+** guarantees about memory fragmentation that are possible if large
+** allocations are avoided. This hint is normally off.
+** </dd>
+**
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
** interpreted as a boolean, which enables or disables the collection of
@@ -2662,25 +2715,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
-** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
-** that SQLite can use for scratch memory. ^(There are three arguments
-** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte
-** aligned memory buffer from which the scratch allocations will be
-** drawn, the size of each scratch allocation (sz),
-** and the maximum number of scratch allocations (N).)^
-** The first argument must be a pointer to an 8-byte aligned buffer
-** of at least sz*N bytes of memory.
-** ^SQLite will not use more than one scratch buffers per thread.
-** ^SQLite will never request a scratch buffer that is more than 6
-** times the database page size.
-** ^If SQLite needs needs additional
-** scratch memory beyond what is provided by this configuration option, then
-** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
-** ^When the application provides any amount of scratch memory using
-** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
-** [sqlite3_malloc|heap allocations].
-** This can help [Robson proof|prevent memory allocation failures] due to heap
-** fragmentation in low-memory embedded systems.
+** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
@@ -2716,8 +2751,7 @@ struct sqlite3_mem_methods {
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
** <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_SCRATCH] and
-** [SQLITE_CONFIG_PAGECACHE].
+** beyond those provided for by [SQLITE_CONFIG_PAGECACHE].
** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
** [SQLITE_ERROR] if invoked otherwise.
@@ -2910,7 +2944,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
@@ -2931,6 +2965,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */
+#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -4131,10 +4166,10 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** ^If [URI filename] interpretation is enabled, and the filename argument
** begins with "file:", then the filename is interpreted as a URI. ^URI
** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
-** set in the fourth argument to sqlite3_open_v2(), or if it has
+** set in the third argument to sqlite3_open_v2(), or if it has
** been enabled globally using the [SQLITE_CONFIG_URI] option with the
** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
-** As of SQLite version 3.7.7, URI filename interpretation is turned off
+** URI filename interpretation is turned off
** by default, but future releases of SQLite might enable URI filename
** interpretation by default. See "[URI filenames]" for additional
** information.
@@ -4808,8 +4843,9 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
** implementation of [application-defined SQL functions] are protected.
** ^The sqlite3_value object returned by
** [sqlite3_column_value()] is unprotected.
-** Unprotected sqlite3_value objects may only be used with
-** [sqlite3_result_value()] and [sqlite3_bind_value()].
+** Unprotected sqlite3_value objects may only be used as arguments
+** to [sqlite3_result_value()], [sqlite3_bind_value()], and
+** [sqlite3_value_dup()].
** The [sqlite3_value_blob | sqlite3_value_type()] family of
** interfaces require protected sqlite3_value objects.
*/
@@ -7232,15 +7268,20 @@ struct sqlite3_index_info {
** 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_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
/*
** CAPI3REF: Register A Virtual Table Implementation
@@ -7992,7 +8033,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_RESERVE 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
+#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
@@ -8051,8 +8092,7 @@ SQLITE_API int sqlite3_status64(
** <dd>This parameter is the current amount of memory checked out
** using [sqlite3_malloc()], either directly or indirectly. The
** figure includes calls made to [sqlite3_malloc()] by the application
-** and internal memory usage by the SQLite library. Scratch memory
-** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache
+** and internal memory usage by the SQLite library. Auxiliary page-cache
** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in
** this parameter. The amount returned is the sum of the allocation
** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
@@ -8090,29 +8130,14 @@ SQLITE_API int sqlite3_status64(
** *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>
-** <dd>This parameter returns the number of allocations used out of the
-** [scratch memory allocator] configured using
-** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not
-** in bytes. Since a single thread may only have one scratch allocation
-** outstanding at time, this parameter also reports the number of threads
-** using scratch memory at the same time.</dd>)^
+** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
+** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
-** <dd>This parameter returns the number of bytes of scratch memory
-** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
-** buffer and where forced to overflow to [sqlite3_malloc()]. The values
-** returned include overflows because the requested allocation was too
-** larger (that is, because the requested allocation was larger than the
-** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer
-** slots were available.
-** </dd>)^
-**
-** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
-** <dd>This parameter records the largest memory allocation request
-** handed to [scratch memory allocator]. Only the value returned in the
-** *pHighwater parameter to [sqlite3_status()] is of interest.
-** The value written into the *pCurrent parameter is undefined.</dd>)^
+** <dd>No longer used.</dd>
+**
+** [[SQLITE_STATUS_SCRATCH_SIZE]] <dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
+** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
** <dd>The *pHighwater parameter records the deepest parser stack.
@@ -8125,12 +8150,12 @@ SQLITE_API int sqlite3_status64(
#define SQLITE_STATUS_MEMORY_USED 0
#define SQLITE_STATUS_PAGECACHE_USED 1
#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2
-#define SQLITE_STATUS_SCRATCH_USED 3
-#define SQLITE_STATUS_SCRATCH_OVERFLOW 4
+#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */
+#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */
#define SQLITE_STATUS_MALLOC_SIZE 5
#define SQLITE_STATUS_PARSER_STACK 6
#define SQLITE_STATUS_PAGECACHE_SIZE 7
-#define SQLITE_STATUS_SCRATCH_SIZE 8
+#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */
#define SQLITE_STATUS_MALLOC_COUNT 9
/*
@@ -10250,8 +10275,8 @@ SQLITE_API int sqlite3session_diff(
*/
SQLITE_API int sqlite3session_patchset(
sqlite3_session *pSession, /* Session object */
- int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
- void **ppPatchset /* OUT: Buffer containing changeset */
+ int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */
+ void **ppPatchset /* OUT: Buffer containing patchset */
);
/*
@@ -11018,12 +11043,12 @@ SQLITE_API int sqlite3changeset_apply(
**
** <table border=1 style="margin-left:8ex;margin-right:8ex">
** <tr><th>Streaming function<th>Non-streaming equivalent</th>
-** <tr><td>sqlite3changeset_apply_str<td>[sqlite3changeset_apply]
-** <tr><td>sqlite3changeset_concat_str<td>[sqlite3changeset_concat]
-** <tr><td>sqlite3changeset_invert_str<td>[sqlite3changeset_invert]
-** <tr><td>sqlite3changeset_start_str<td>[sqlite3changeset_start]
-** <tr><td>sqlite3session_changeset_str<td>[sqlite3session_changeset]
-** <tr><td>sqlite3session_patchset_str<td>[sqlite3session_patchset]
+** <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply]
+** <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
@@ -12244,6 +12269,21 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
#endif
/*
+** Some conditionals are optimizations only. In other words, if the
+** conditionals are replaced with a constant 1 (true) or 0 (false) then
+** the correct answer is still obtained, though perhaps not as quickly.
+**
+** The following macros mark these optimizations conditionals.
+*/
+#if defined(SQLITE_MUTATION_TEST)
+# define OK_IF_ALWAYS_TRUE(X) (1)
+# define OK_IF_ALWAYS_FALSE(X) (0)
+#else
+# define OK_IF_ALWAYS_TRUE(X) (X)
+# define OK_IF_ALWAYS_FALSE(X) (X)
+#endif
+
+/*
** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is
** defined. We need to defend against those failures when testing with
** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches
@@ -12437,63 +12477,63 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#define TK_AS 24
#define TK_WITHOUT 25
#define TK_COMMA 26
-#define TK_ID 27
-#define TK_ABORT 28
-#define TK_ACTION 29
-#define TK_AFTER 30
-#define TK_ANALYZE 31
-#define TK_ASC 32
-#define TK_ATTACH 33
-#define TK_BEFORE 34
-#define TK_BY 35
-#define TK_CASCADE 36
-#define TK_CAST 37
-#define TK_COLUMNKW 38
-#define TK_CONFLICT 39
-#define TK_DATABASE 40
-#define TK_DESC 41
-#define TK_DETACH 42
-#define TK_EACH 43
-#define TK_FAIL 44
-#define TK_FOR 45
-#define TK_IGNORE 46
-#define TK_INITIALLY 47
-#define TK_INSTEAD 48
-#define TK_LIKE_KW 49
-#define TK_MATCH 50
-#define TK_NO 51
-#define TK_KEY 52
-#define TK_OF 53
-#define TK_OFFSET 54
-#define TK_PRAGMA 55
-#define TK_RAISE 56
-#define TK_RECURSIVE 57
-#define TK_REPLACE 58
-#define TK_RESTRICT 59
-#define TK_ROW 60
-#define TK_TRIGGER 61
-#define TK_VACUUM 62
-#define TK_VIEW 63
-#define TK_VIRTUAL 64
-#define TK_WITH 65
-#define TK_REINDEX 66
-#define TK_RENAME 67
-#define TK_CTIME_KW 68
-#define TK_ANY 69
-#define TK_OR 70
-#define TK_AND 71
-#define TK_IS 72
-#define TK_BETWEEN 73
-#define TK_IN 74
-#define TK_ISNULL 75
-#define TK_NOTNULL 76
-#define TK_NE 77
-#define TK_EQ 78
-#define TK_GT 79
-#define TK_LE 80
-#define TK_LT 81
-#define TK_GE 82
-#define TK_ESCAPE 83
+#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_FOR 61
+#define TK_IGNORE 62
+#define TK_INITIALLY 63
+#define TK_INSTEAD 64
+#define TK_NO 65
+#define TK_KEY 66
+#define TK_OF 67
+#define TK_OFFSET 68
+#define TK_PRAGMA 69
+#define TK_RAISE 70
+#define TK_RECURSIVE 71
+#define TK_REPLACE 72
+#define TK_RESTRICT 73
+#define TK_ROW 74
+#define TK_TRIGGER 75
+#define TK_VACUUM 76
+#define TK_VIEW 77
+#define TK_VIRTUAL 78
+#define TK_WITH 79
+#define TK_REINDEX 80
+#define TK_RENAME 81
+#define TK_CTIME_KW 82
+#define TK_ANY 83
#define TK_BITAND 84
#define TK_BITOR 85
#define TK_LSHIFT 86
@@ -12553,28 +12593,23 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#define TK_INDEX 140
#define TK_ALTER 141
#define TK_ADD 142
-#define TK_TO_TEXT 143
-#define TK_TO_BLOB 144
-#define TK_TO_NUMERIC 145
-#define TK_TO_INT 146
-#define TK_TO_REAL 147
-#define TK_ISNOT 148
-#define TK_END_OF_FILE 149
-#define TK_UNCLOSED_STRING 150
-#define TK_FUNCTION 151
-#define TK_COLUMN 152
-#define TK_AGG_FUNCTION 153
-#define TK_AGG_COLUMN 154
-#define TK_UMINUS 155
-#define TK_UPLUS 156
-#define TK_REGISTER 157
-#define TK_VECTOR 158
-#define TK_SELECT_COLUMN 159
-#define TK_IF_NULL_ROW 160
-#define TK_ASTERISK 161
-#define TK_SPAN 162
-#define TK_SPACE 163
-#define TK_ILLEGAL 164
+#define TK_ISNOT 143
+#define TK_FUNCTION 144
+#define TK_COLUMN 145
+#define TK_AGG_FUNCTION 146
+#define TK_AGG_COLUMN 147
+#define TK_UMINUS 148
+#define TK_UPLUS 149
+#define TK_REGISTER 150
+#define TK_VECTOR 151
+#define TK_SELECT_COLUMN 152
+#define TK_IF_NULL_ROW 153
+#define TK_ASTERISK 154
+#define TK_SPAN 155
+#define TK_END_OF_FILE 156
+#define TK_UNCLOSED_STRING 157
+#define TK_SPACE 158
+#define TK_ILLEGAL 159
/* The token codes above must all fit in 8 bits */
#define TKFLG_MASK 0xff
@@ -12695,6 +12730,15 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#endif
/*
+** 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.
+*/
+#if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+#error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+#endif
+
+/*
** GCC does not define the offsetof() macro so we'll have to do it
** ourselves.
*/
@@ -12992,7 +13036,7 @@ typedef INT16_TYPE LogEst;
** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
** the Select query generator tracing logic is turned on.
*/
-#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE)
+#if defined(SQLITE_ENABLE_SELECTTRACE)
# define SELECTTRACE_ENABLED 1
#else
# define SELECTTRACE_ENABLED 0
@@ -13398,6 +13442,7 @@ SQLITE_PRIVATE int sqlite3BtreeCursor(
struct KeyInfo*, /* First argument to compare function */
BtCursor *pCursor /* Space to write cursor structure */
);
+SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void);
SQLITE_PRIVATE int sqlite3BtreeCursorSize(void);
SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
@@ -13716,87 +13761,87 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Savepoint 0
#define OP_AutoCommit 1
#define OP_Transaction 2
-#define OP_SorterNext 3
-#define OP_PrevIfOpen 4
-#define OP_NextIfOpen 5
-#define OP_Prev 6
-#define OP_Next 7
+#define OP_SorterNext 3 /* jump */
+#define OP_PrevIfOpen 4 /* jump */
+#define OP_NextIfOpen 5 /* jump */
+#define OP_Prev 6 /* jump */
+#define OP_Next 7 /* jump */
#define OP_Checkpoint 8
#define OP_JournalMode 9
#define OP_Vacuum 10
-#define OP_VFilter 11 /* synopsis: iplan=r[P3] zplan='P4' */
+#define OP_VFilter 11 /* jump, synopsis: iplan=r[P3] zplan='P4' */
#define OP_VUpdate 12 /* synopsis: data=r[P3@P2] */
-#define OP_Goto 13
-#define OP_Gosub 14
-#define OP_InitCoroutine 15
-#define OP_Yield 16
-#define OP_MustBeInt 17
-#define OP_Jump 18
+#define OP_Goto 13 /* jump */
+#define OP_Gosub 14 /* jump */
+#define OP_InitCoroutine 15 /* jump */
+#define OP_Yield 16 /* jump */
+#define OP_MustBeInt 17 /* jump */
+#define OP_Jump 18 /* jump */
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
-#define OP_Once 20
-#define OP_If 21
-#define OP_IfNot 22
-#define OP_IfNullRow 23 /* synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
-#define OP_SeekLT 24 /* synopsis: key=r[P3@P4] */
-#define OP_SeekLE 25 /* synopsis: key=r[P3@P4] */
-#define OP_SeekGE 26 /* synopsis: key=r[P3@P4] */
-#define OP_SeekGT 27 /* synopsis: key=r[P3@P4] */
-#define OP_NoConflict 28 /* synopsis: key=r[P3@P4] */
-#define OP_NotFound 29 /* synopsis: key=r[P3@P4] */
-#define OP_Found 30 /* synopsis: key=r[P3@P4] */
-#define OP_SeekRowid 31 /* synopsis: intkey=r[P3] */
-#define OP_NotExists 32 /* synopsis: intkey=r[P3] */
-#define OP_Last 33
-#define OP_IfSmaller 34
-#define OP_SorterSort 35
-#define OP_Sort 36
-#define OP_Rewind 37
-#define OP_IdxLE 38 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGT 39 /* synopsis: key=r[P3@P4] */
-#define OP_IdxLT 40 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGE 41 /* synopsis: key=r[P3@P4] */
-#define OP_RowSetRead 42 /* synopsis: r[P3]=rowset(P1) */
-#define OP_RowSetTest 43 /* synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program 44
-#define OP_FkIfZero 45 /* synopsis: if fkctr[P1]==0 goto P2 */
-#define OP_IfPos 46 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
-#define OP_IfNotZero 47 /* synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
-#define OP_DecrJumpZero 48 /* synopsis: if (--r[P1])==0 goto P2 */
-#define OP_IncrVacuum 49
-#define OP_VNext 50
-#define OP_Init 51 /* synopsis: Start at P2 */
-#define OP_Return 52
-#define OP_EndCoroutine 53
-#define OP_HaltIfNull 54 /* synopsis: if r[P3]=null halt */
-#define OP_Halt 55
-#define OP_Integer 56 /* synopsis: r[P2]=P1 */
-#define OP_Int64 57 /* synopsis: r[P2]=P4 */
-#define OP_String 58 /* synopsis: r[P2]='P4' (len=P1) */
-#define OP_Null 59 /* synopsis: r[P2..P3]=NULL */
-#define OP_SoftNull 60 /* synopsis: r[P1]=NULL */
-#define OP_Blob 61 /* synopsis: r[P2]=P4 (len=P1) */
-#define OP_Variable 62 /* synopsis: r[P2]=parameter(P1,P4) */
-#define OP_Move 63 /* synopsis: r[P2@P3]=r[P1@P3] */
-#define OP_Copy 64 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
-#define OP_SCopy 65 /* synopsis: r[P2]=r[P1] */
-#define OP_IntCopy 66 /* synopsis: r[P2]=r[P1] */
-#define OP_ResultRow 67 /* synopsis: output=r[P1@P2] */
-#define OP_CollSeq 68
-#define OP_AddImm 69 /* synopsis: r[P1]=r[P1]+P2 */
-#define OP_Or 70 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
-#define OP_And 71 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_RealAffinity 72
-#define OP_Cast 73 /* synopsis: affinity(r[P1]) */
-#define OP_Permutation 74
-#define OP_IsNull 75 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
-#define OP_NotNull 76 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
-#define OP_Ne 77 /* same as TK_NE, synopsis: IF r[P3]!=r[P1] */
-#define OP_Eq 78 /* same as TK_EQ, synopsis: IF r[P3]==r[P1] */
-#define OP_Gt 79 /* same as TK_GT, synopsis: IF r[P3]>r[P1] */
-#define OP_Le 80 /* same as TK_LE, synopsis: IF r[P3]<=r[P1] */
-#define OP_Lt 81 /* same as TK_LT, synopsis: IF r[P3]<r[P1] */
-#define OP_Ge 82 /* same as TK_GE, synopsis: IF r[P3]>=r[P1] */
-#define OP_ElseNotEq 83 /* same as TK_ESCAPE */
+#define OP_Once 20 /* jump */
+#define OP_If 21 /* jump */
+#define OP_IfNot 22 /* jump */
+#define OP_IfNullRow 23 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_SeekLT 24 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekLE 25 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekGE 26 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekGT 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_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_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] */
+#define OP_Eq 53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
+#define OP_Gt 54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
+#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_Return 63
+#define OP_EndCoroutine 64
+#define OP_HaltIfNull 65 /* synopsis: if r[P3]=null halt */
+#define OP_Halt 66
+#define OP_Integer 67 /* synopsis: r[P2]=P1 */
+#define OP_Int64 68 /* synopsis: r[P2]=P4 */
+#define OP_String 69 /* synopsis: r[P2]='P4' (len=P1) */
+#define OP_Null 70 /* synopsis: r[P2..P3]=NULL */
+#define OP_SoftNull 71 /* synopsis: r[P1]=NULL */
+#define OP_Blob 72 /* synopsis: r[P2]=P4 (len=P1) */
+#define OP_Variable 73 /* synopsis: r[P2]=parameter(P1,P4) */
+#define OP_Move 74 /* synopsis: r[P2@P3]=r[P1@P3] */
+#define OP_Copy 75 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
+#define OP_SCopy 76 /* synopsis: r[P2]=r[P1] */
+#define OP_IntCopy 77 /* synopsis: r[P2]=r[P1] */
+#define OP_ResultRow 78 /* synopsis: output=r[P1@P2] */
+#define OP_CollSeq 79
+#define OP_AddImm 80 /* synopsis: r[P1]=r[P1]+P2 */
+#define OP_RealAffinity 81
+#define OP_Cast 82 /* synopsis: affinity(r[P1]) */
+#define OP_Permutation 83
#define OP_BitAnd 84 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
#define OP_BitOr 85 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
#define OP_ShiftLeft 86 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
@@ -13838,17 +13883,17 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_RowData 122 /* synopsis: r[P2]=data */
#define OP_Rowid 123 /* synopsis: r[P2]=rowid */
#define OP_NullRow 124
-#define OP_SorterInsert 125 /* synopsis: key=r[P2] */
-#define OP_IdxInsert 126 /* synopsis: key=r[P2] */
-#define OP_IdxDelete 127 /* synopsis: key=r[P2@P3] */
-#define OP_DeferredSeek 128 /* synopsis: Move P3 to P1.rowid if needed */
-#define OP_IdxRowid 129 /* synopsis: r[P2]=rowid */
-#define OP_Destroy 130
-#define OP_Clear 131
+#define OP_SeekEnd 125
+#define OP_SorterInsert 126 /* synopsis: key=r[P2] */
+#define OP_IdxInsert 127 /* synopsis: key=r[P2] */
+#define OP_IdxDelete 128 /* synopsis: key=r[P2@P3] */
+#define OP_DeferredSeek 129 /* synopsis: Move P3 to P1.rowid if needed */
+#define OP_IdxRowid 130 /* synopsis: r[P2]=rowid */
+#define OP_Destroy 131
#define OP_Real 132 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_ResetSorter 133
-#define OP_CreateIndex 134 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_CreateTable 135 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_Clear 133
+#define OP_ResetSorter 134
+#define OP_CreateBtree 135 /* synopsis: r[P2]=root iDb=P1 flags=P3 */
#define OP_SqlExec 136
#define OP_ParseSchema 137
#define OP_LoadAnalysis 138
@@ -13898,18 +13943,18 @@ typedef struct VdbeOpList VdbeOpList;
/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x01,\
/* 24 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\
/* 32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
-/* 40 */ 0x01, 0x01, 0x23, 0x0b, 0x01, 0x01, 0x03, 0x03,\
-/* 48 */ 0x03, 0x01, 0x01, 0x01, 0x02, 0x02, 0x08, 0x00,\
-/* 56 */ 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00,\
-/* 64 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x02, 0x26, 0x26,\
-/* 72 */ 0x02, 0x02, 0x00, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\
-/* 80 */ 0x0b, 0x0b, 0x0b, 0x01, 0x26, 0x26, 0x26, 0x26,\
+/* 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, 0x02,\
+/* 64 */ 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00,\
+/* 72 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
+/* 80 */ 0x02, 0x02, 0x02, 0x00, 0x26, 0x26, 0x26, 0x26,\
/* 88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00, 0x12,\
/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 112 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\
-/* 120 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x04, 0x00,\
-/* 128 */ 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10,\
+/* 120 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, 0x04,\
+/* 128 */ 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10,\
/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,\
/* 144 */ 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00,\
/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
@@ -13922,7 +13967,7 @@ typedef struct VdbeOpList VdbeOpList;
** generated this include file strives to group all JUMP opcodes
** together near the beginning of the list.
*/
-#define SQLITE_MX_JUMP_OPCODE 83 /* Maximum JUMP opcode */
+#define SQLITE_MX_JUMP_OPCODE 62 /* Maximum JUMP opcode */
/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/
@@ -14240,6 +14285,7 @@ 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*);
@@ -14376,6 +14422,8 @@ struct PgHdr {
i16 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
+ ** PgHdr object is not dirty */
};
/* Bit values for PgHdr.flags */
@@ -14757,10 +14805,12 @@ 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 *);
@@ -14969,6 +15019,7 @@ 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 */
/*
** The number of different kinds of things that can be limited
@@ -15000,9 +15051,9 @@ struct Lookaside {
u32 bDisable; /* Only operate the lookaside when zero */
u16 sz; /* Size of each buffer in bytes */
u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */
- int nOut; /* Number of buffers currently checked out */
- int mxOut; /* Highwater mark for nOut */
- int anStat[3]; /* 0: hits. 1: size misses. 2: full misses */
+ u32 nSlot; /* Number of lookaside slots allocated */
+ u32 anStat[3]; /* 0: hits. 1: size misses. 2: full misses */
+ LookasideSlot *pInit; /* List of buffers not previously used */
LookasideSlot *pFree; /* List of available buffers */
void *pStart; /* First byte of available memory space */
void *pEnd; /* First byte past end of available space */
@@ -15081,9 +15132,11 @@ struct sqlite3 {
sqlite3_mutex *mutex; /* Connection mutex */
Db *aDb; /* All backends */
int nDb; /* Number of backends currently in use */
- int flags; /* Miscellaneous flags. See below */
+ u32 mDbFlags; /* flags recording internal state */
+ u32 flags; /* flags settable by pragmas. See below */
i64 lastRowid; /* ROWID of most recent insert (see above) */
i64 szMmap; /* Default mmap_size setting */
+ 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 errMask; /* & result codes with this before returning */
@@ -15235,18 +15288,13 @@ struct sqlite3 {
#define SQLITE_ForeignKeys 0x00004000 /* Enforce foreign key constraints */
#define SQLITE_AutoIndex 0x00008000 /* Enable automatic indexes */
#define SQLITE_LoadExtension 0x00010000 /* Enable load_extension */
-#define SQLITE_EnableTrigger 0x00020000 /* True to enable triggers */
-#define SQLITE_DeferFKs 0x00040000 /* Defer all FK constraints */
-#define SQLITE_QueryOnly 0x00080000 /* Disable database changes */
-#define SQLITE_CellSizeCk 0x00100000 /* Check btree cell sizes on load */
-#define SQLITE_Fts3Tokenizer 0x00200000 /* Enable fts3_tokenizer(2) */
-#define SQLITE_EnableQPSG 0x00400000 /* Query Planner Stability Guarantee */
-/* The next four values are not used by PRAGMAs or by sqlite3_dbconfig() and
-** could be factored out into a separate bit vector of the sqlite3 object. */
-#define SQLITE_InternChanges 0x00800000 /* Uncommitted Hash table changes */
-#define SQLITE_LoadExtFunc 0x01000000 /* Enable load_extension() SQL func */
-#define SQLITE_PreferBuiltin 0x02000000 /* Preference to built-in funcs */
-#define SQLITE_Vacuum 0x04000000 /* Currently in a VACUUM */
+#define SQLITE_LoadExtFunc 0x00020000 /* Enable load_extension() SQL func */
+#define SQLITE_EnableTrigger 0x00040000 /* True to enable triggers */
+#define SQLITE_DeferFKs 0x00080000 /* Defer all FK constraints */
+#define SQLITE_QueryOnly 0x00100000 /* Disable database changes */
+#define SQLITE_CellSizeCk 0x00200000 /* Check btree cell sizes on load */
+#define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */
+#define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee */
/* Flags used only if debugging */
#ifdef SQLITE_DEBUG
#define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */
@@ -15256,6 +15304,12 @@ struct sqlite3 {
#define SQLITE_VdbeEQP 0x80000000 /* Debug EXPLAIN QUERY PLAN */
#endif
+/*
+** Allowed values for sqlite3.mDbFlags
+*/
+#define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */
+#define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */
+#define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */
/*
** Bits of the sqlite3.dbOptFlags field that are used by the
@@ -15266,16 +15320,15 @@ struct sqlite3 {
#define SQLITE_ColumnCache 0x0002 /* Column cache */
#define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */
#define SQLITE_FactorOutConst 0x0008 /* Constant factoring */
-/* not used 0x0010 // Was: SQLITE_IdxRealAsInt */
-#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
-#define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */
-#define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */
-#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
-#define SQLITE_Transitive 0x0200 /* Transitive constraints */
-#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
+#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_Stat34 0x0800 /* Use STAT3 or STAT4 data */
-#define SQLITE_CountOfView 0x1000 /* The count-of-view optimization */
-#define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */
+ /* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */
#define SQLITE_AllOpts 0xffff /* All optimizations */
/*
@@ -15806,8 +15859,8 @@ struct FKey {
struct KeyInfo {
u32 nRef; /* Number of references to this KeyInfo object */
u8 enc; /* Text encoding - one of the SQLITE_UTF* values */
- u16 nField; /* Number of key columns in the index */
- u16 nXField; /* Number of columns beyond the key columns */
+ u16 nKeyField; /* Number of key columns in the index */
+ u16 nAllField; /* Total columns, including key plus others */
sqlite3 *db; /* The database connection */
u8 *aSortOrder; /* Sort order for each column. */
CollSeq *aColl[1]; /* Collating sequence for each term of the key */
@@ -15854,8 +15907,8 @@ struct UnpackedRecord {
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) */
- i8 r1; /* Value to return if (lhs > rhs) */
- i8 r2; /* Value to return if (rhs < lhs) */
+ i8 r1; /* Value to return if (lhs < rhs) */
+ i8 r2; /* Value to return if (lhs > rhs) */
u8 eqSeen; /* True if an equality comparison has been seen */
};
@@ -16139,7 +16192,8 @@ struct Expr {
** TK_COLUMN: the value of p5 for OP_Column
** TK_AGG_FUNCTION: nesting depth */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
- Table *pTab; /* Table for TK_COLUMN expressions. */
+ Table *pTab; /* Table for TK_COLUMN expressions. Can be NULL
+ ** for a column of an index on an expression */
};
/*
@@ -16227,7 +16281,6 @@ 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 *zName; /* Token associated with this expression */
@@ -16752,7 +16805,7 @@ 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 */
- int addrCrTab; /* Address of OP_CreateTable opcode on CREATE TABLE */
+ int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */
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 */
@@ -16981,11 +17034,10 @@ struct DbFixer {
*/
struct StrAccum {
sqlite3 *db; /* Optional database for lookaside. Can be NULL */
- char *zBase; /* A base allocation. Not from malloc. */
char *zText; /* The string collected so far */
- u32 nChar; /* Length of the string so far */
u32 nAlloc; /* Amount of space allocated in zText */
u32 mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */
+ u32 nChar; /* Length of the string so far */
u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */
u8 printfFlags; /* SQLITE_PRINTF flags below */
};
@@ -17020,6 +17072,7 @@ struct Sqlite3Config {
int bFullMutex; /* True to enable full mutexing */
int bOpenUri; /* True to interpret filenames as URIs */
int bUseCis; /* Use covering indices for full-scans */
+ int bSmallMalloc; /* Avoid large memory allocations if true */
int mxStrlen; /* Maximum string length */
int neverCorrupt; /* Database is always well-formed */
int szLookaside; /* Default lookaside buffer size */
@@ -17033,9 +17086,6 @@ struct Sqlite3Config {
int mnReq, mxReq; /* Min and max heap requests sizes */
sqlite3_int64 szMmap; /* mmap() space per open file */
sqlite3_int64 mxMmap; /* Maximum value for szMmap */
- void *pScratch; /* Scratch memory */
- int szScratch; /* Size of each scratch buffer */
- int nScratch; /* Number of scratch buffers */
void *pPage; /* Page cache memory */
int szPage; /* Size of each page in pPage[] */
int nPage; /* Number of pages in pPage[] */
@@ -17122,6 +17172,7 @@ SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*);
SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*);
SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*);
SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*);
+SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*);
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*);
#endif
@@ -17274,8 +17325,6 @@ 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 *sqlite3ScratchMalloc(int);
-SQLITE_PRIVATE void sqlite3ScratchFree(void*);
SQLITE_PRIVATE void *sqlite3PageMalloc(int);
SQLITE_PRIVATE void sqlite3PageFree(void*);
SQLITE_PRIVATE void sqlite3MemSetDefault(void);
@@ -17331,6 +17380,7 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int);
SQLITE_PRIVATE void sqlite3StatusUp(int, int);
SQLITE_PRIVATE void sqlite3StatusDown(int, int);
SQLITE_PRIVATE void sqlite3StatusHighwater(int, int);
+SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3*,int*);
/* Access to mutexes used by sqlite3_status() */
SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void);
@@ -17767,6 +17817,8 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
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 Expr *sqlite3ExprSkipCollate(Expr*);
@@ -18050,7 +18102,8 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*);
SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *);
#endif
@@ -18136,8 +18189,7 @@ SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8);
#endif
#define MEMTYPE_HEAP 0x01 /* General heap allocations */
#define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */
-#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */
-#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
+#define MEMTYPE_PCACHE 0x04 /* Page cache allocations */
/*
** Threading interface
@@ -18147,6 +18199,9 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**);
#endif
+#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)
+SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3*);
+#endif
#if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*);
#endif
@@ -18366,6 +18421,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_THREADSAFE==1, /* bFullMutex */
SQLITE_USE_URI, /* bOpenUri */
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
+ 0, /* bSmallMalloc */
0x7ffffffe, /* mxStrlen */
0, /* neverCorrupt */
SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
@@ -18378,9 +18434,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, 0, /* mnHeap, mxHeap */
SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */
SQLITE_MAX_MMAP_SIZE, /* mxMmap */
- (void*)0, /* pScratch */
- 0, /* szScratch */
- 0, /* nScratch */
(void*)0, /* pPage */
0, /* szPage */
SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */
@@ -18582,18 +18635,18 @@ struct VdbeCursor {
u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
int seekResult; /* Result of previous sqlite3BtreeMoveto() or 0
** if there have been no prior seeks on the cursor. */
- /* NB: seekResult does not distinguish between "no seeks have ever occurred
- ** on this cursor" and "the most recent seek was an exact match". */
+ /* seekResult does not distinguish between "no seeks have ever occurred
+ ** on this cursor" and "the most recent seek was an exact match".
+ ** For CURTYPE_PSEUDO, seekResult is the register holding the record */
/* When a new VdbeCursor is allocated, only the fields above are zeroed.
** The fields that follow are uninitialized, and must be individually
** initialized prior to first use. */
VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
union {
- BtCursor *pCursor; /* CURTYPE_BTREE. Btree cursor */
- sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */
- int pseudoTableReg; /* CURTYPE_PSEUDO. Reg holding content. */
- VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
+ BtCursor *pCursor; /* CURTYPE_BTREE or _PSEUDO. Btree cursor */
+ sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */
+ VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
} uc;
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
u32 iHdrOffset; /* Offset to next unparsed byte of the header */
@@ -19150,7 +19203,6 @@ SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){
: sqlite3MallocMutex()) );
assert( op==SQLITE_STATUS_MALLOC_SIZE
|| op==SQLITE_STATUS_PAGECACHE_SIZE
- || op==SQLITE_STATUS_SCRATCH_SIZE
|| op==SQLITE_STATUS_PARSER_STACK );
if( newValue>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = newValue;
@@ -19200,6 +19252,28 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
}
/*
+** Return the number of LookasideSlot elements on the linked list
+*/
+static u32 countLookasideSlots(LookasideSlot *p){
+ u32 cnt = 0;
+ while( p ){
+ p = p->pNext;
+ cnt++;
+ }
+ return cnt;
+}
+
+/*
+** Count the number of slots of lookaside memory that are outstanding
+*/
+SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
+ u32 nInit = countLookasideSlots(db->lookaside.pInit);
+ u32 nFree = countLookasideSlots(db->lookaside.pFree);
+ if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
+ return db->lookaside.nSlot - (nInit+nFree);
+}
+
+/*
** Query status information for a single database connection
*/
SQLITE_API int sqlite3_db_status(
@@ -19218,10 +19292,15 @@ SQLITE_API int sqlite3_db_status(
sqlite3_mutex_enter(db->mutex);
switch( op ){
case SQLITE_DBSTATUS_LOOKASIDE_USED: {
- *pCurrent = db->lookaside.nOut;
- *pHighwater = db->lookaside.mxOut;
+ *pCurrent = sqlite3LookasideUsed(db, pHighwater);
if( resetFlag ){
- db->lookaside.mxOut = db->lookaside.nOut;
+ LookasideSlot *p = db->lookaside.pFree;
+ if( p ){
+ while( p->pNext ) p = p->pNext;
+ p->pNext = db->lookaside.pInit;
+ db->lookaside.pInit = db->lookaside.pFree;
+ db->lookaside.pFree = 0;
+ }
}
break;
}
@@ -20735,7 +20814,7 @@ SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){
}
SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){
DO_OS_MALLOC_TEST(id);
- return id->pMethods->xSync(id, flags);
+ return flags ? id->pMethods->xSync(id, flags) : SQLITE_OK;
}
SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
DO_OS_MALLOC_TEST(id);
@@ -20790,6 +20869,7 @@ SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
return id->pMethods->xDeviceCharacteristics(id);
}
+#ifndef SQLITE_OMIT_WAL
SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
return id->pMethods->xShmLock(id, offset, n, flags);
}
@@ -20809,6 +20889,7 @@ SQLITE_PRIVATE int sqlite3OsShmMap(
DO_OS_MALLOC_TEST(id);
return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
}
+#endif /* SQLITE_OMIT_WAL */
#if SQLITE_MAX_MMAP_SIZE>0
/* The real implementation of xFetch and xUnfetch */
@@ -24806,14 +24887,6 @@ SQLITE_API int sqlite3_release_memory(int n){
}
/*
-** An instance of the following object records the location of
-** each unused scratch buffer.
-*/
-typedef struct ScratchFreeslot {
- struct ScratchFreeslot *pNext; /* Next unused scratch buffer */
-} ScratchFreeslot;
-
-/*
** State information local to the memory allocation subsystem.
*/
static SQLITE_WSD struct Mem0Global {
@@ -24821,21 +24894,11 @@ static SQLITE_WSD struct Mem0Global {
sqlite3_int64 alarmThreshold; /* The soft heap limit */
/*
- ** Pointers to the end of sqlite3GlobalConfig.pScratch memory
- ** (so that a range test can be used to determine if an allocation
- ** being freed came from pScratch) and a pointer to the list of
- ** unused scratch allocations.
- */
- void *pScratchEnd;
- ScratchFreeslot *pScratchFree;
- u32 nScratchFree;
-
- /*
** True if heap is nearly "full" where "full" is defined by the
** sqlite3_soft_heap_limit() setting.
*/
int nearlyFull;
-} mem0 = { 0, 0, 0, 0, 0, 0 };
+} mem0 = { 0, 0, 0 };
#define mem0 GLOBAL(struct Mem0Global, mem0)
@@ -24905,28 +24968,6 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
}
memset(&mem0, 0, sizeof(mem0));
mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
- if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
- && sqlite3GlobalConfig.nScratch>0 ){
- int i, n, sz;
- ScratchFreeslot *pSlot;
- sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch);
- sqlite3GlobalConfig.szScratch = sz;
- pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch;
- n = sqlite3GlobalConfig.nScratch;
- mem0.pScratchFree = pSlot;
- mem0.nScratchFree = n;
- for(i=0; i<n-1; i++){
- pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot);
- pSlot = pSlot->pNext;
- }
- pSlot->pNext = 0;
- mem0.pScratchEnd = (void*)&pSlot[1];
- }else{
- mem0.pScratchEnd = 0;
- sqlite3GlobalConfig.pScratch = 0;
- sqlite3GlobalConfig.szScratch = 0;
- sqlite3GlobalConfig.nScratch = 0;
- }
if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
|| sqlite3GlobalConfig.nPage<=0 ){
sqlite3GlobalConfig.pPage = 0;
@@ -25078,105 +25119,6 @@ SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){
}
/*
-** Each thread may only have a single outstanding allocation from
-** xScratchMalloc(). We verify this constraint in the single-threaded
-** case by setting scratchAllocOut to 1 when an allocation
-** is outstanding clearing it when the allocation is freed.
-*/
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
-static int scratchAllocOut = 0;
-#endif
-
-
-/*
-** Allocate memory that is to be used and released right away.
-** This routine is similar to alloca() in that it is not intended
-** for situations where the memory might be held long-term. This
-** routine is intended to get memory to old large transient data
-** structures that would not normally fit on the stack of an
-** embedded processor.
-*/
-SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
- void *p;
- assert( n>0 );
-
- sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusHighwater(SQLITE_STATUS_SCRATCH_SIZE, n);
- if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){
- p = mem0.pScratchFree;
- mem0.pScratchFree = mem0.pScratchFree->pNext;
- mem0.nScratchFree--;
- sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1);
- sqlite3_mutex_leave(mem0.mutex);
- }else{
- sqlite3_mutex_leave(mem0.mutex);
- p = sqlite3Malloc(n);
- if( sqlite3GlobalConfig.bMemstat && p ){
- sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
- sqlite3_mutex_leave(mem0.mutex);
- }
- sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
- }
- assert( sqlite3_mutex_notheld(mem0.mutex) );
-
-
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch
- ** buffers per thread.
- **
- ** This can only be checked in single-threaded mode.
- */
- assert( scratchAllocOut==0 );
- if( p ) scratchAllocOut++;
-#endif
-
- return p;
-}
-SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
- if( p ){
-
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than two scratch allocation per thread
- ** is outstanding at one time. (This is only checked in the
- ** single-threaded case since checking in the multi-threaded case
- ** would be much more complicated.) */
- assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
- scratchAllocOut--;
-#endif
-
- if( SQLITE_WITHIN(p, sqlite3GlobalConfig.pScratch, mem0.pScratchEnd) ){
- /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */
- ScratchFreeslot *pSlot;
- pSlot = (ScratchFreeslot*)p;
- sqlite3_mutex_enter(mem0.mutex);
- pSlot->pNext = mem0.pScratchFree;
- mem0.pScratchFree = pSlot;
- mem0.nScratchFree++;
- assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
- sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1);
- sqlite3_mutex_leave(mem0.mutex);
- }else{
- /* Release memory back to the heap */
- assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
- assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) );
- sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
- if( sqlite3GlobalConfig.bMemstat ){
- int iSize = sqlite3MallocSize(p);
- sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize);
- sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize);
- sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
- sqlite3GlobalConfig.m.xFree(p);
- sqlite3_mutex_leave(mem0.mutex);
- }else{
- sqlite3GlobalConfig.m.xFree(p);
- }
- }
- }
-}
-
-/*
** TRUE if p is a lookaside memory allocation from db
*/
#ifndef SQLITE_OMIT_LOOKASIDE
@@ -25266,7 +25208,6 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
#endif
pBuf->pNext = db->lookaside.pFree;
db->lookaside.pFree = pBuf;
- db->lookaside.nOut--;
return;
}
}
@@ -25427,16 +25368,16 @@ SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
assert( db->mallocFailed==0 );
if( n>db->lookaside.sz ){
db->lookaside.anStat[1]++;
- }else if( (pBuf = db->lookaside.pFree)==0 ){
- db->lookaside.anStat[2]++;
- }else{
+ }else if( (pBuf = db->lookaside.pFree)!=0 ){
db->lookaside.pFree = pBuf->pNext;
- db->lookaside.nOut++;
db->lookaside.anStat[0]++;
- if( db->lookaside.nOut>db->lookaside.mxOut ){
- db->lookaside.mxOut = db->lookaside.nOut;
- }
return (void*)pBuf;
+ }else if( (pBuf = db->lookaside.pInit)!=0 ){
+ db->lookaside.pInit = pBuf->pNext;
+ db->lookaside.anStat[0]++;
+ return (void*)pBuf;
+ }else{
+ db->lookaside.anStat[2]++;
}
}else if( db->mallocFailed ){
return 0;
@@ -26274,7 +26215,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
if( precision>=0 ){
for(length=0; length<precision && bufpt[length]; length++){}
}else{
- length = sqlite3Strlen30(bufpt);
+ length = 0x7fffffff & (int)strlen(bufpt);
}
break;
case etSQLESCAPE: /* Escape ' characters */
@@ -26400,7 +26341,6 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
}else{
char *zOld = isMalloced(p) ? p->zText : 0;
i64 szNew = p->nChar;
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
szNew += N + 1;
if( szNew+p->nChar<=p->mxAlloc ){
/* Force exponential buffer size growth as long as it does not overflow,
@@ -26442,7 +26382,6 @@ SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){
if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){
return;
}
- assert( (p->zText==p->zBase)==!isMalloced(p) );
while( (N--)>0 ) p->zText[p->nChar++] = c;
}
@@ -26460,7 +26399,6 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
memcpy(&p->zText[p->nChar], z, N);
p->nChar += N;
}
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
}
/*
@@ -26495,19 +26433,20 @@ SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
** pointer if any kind of error was encountered.
*/
static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
+ char *zText;
assert( p->mxAlloc>0 && !isMalloced(p) );
- p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
- if( p->zText ){
- memcpy(p->zText, p->zBase, p->nChar+1);
+ zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
+ if( zText ){
+ memcpy(zText, p->zText, p->nChar+1);
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
}else{
setStrAccumError(p, STRACCUM_NOMEM);
}
- return p->zText;
+ p->zText = zText;
+ return zText;
}
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
if( p->zText ){
- assert( (p->zText==p->zBase)==!isMalloced(p) );
p->zText[p->nChar] = 0;
if( p->mxAlloc>0 && !isMalloced(p) ){
return strAccumFinishRealloc(p);
@@ -26520,7 +26459,6 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
** Reset an StrAccum string. Reclaim all malloced memory.
*/
SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
if( isMalloced(p) ){
sqlite3DbFree(p->db, p->zText);
p->printfFlags &= ~SQLITE_PRINTF_MALLOCED;
@@ -26543,11 +26481,11 @@ SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
** allocations will ever occur.
*/
SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){
- p->zText = p->zBase = zBase;
+ p->zText = zBase;
p->db = db;
- p->nChar = 0;
p->nAlloc = n;
p->mxAlloc = mx;
+ p->nChar = 0;
p->accError = 0;
p->printfFlags = 0;
}
@@ -28708,7 +28646,11 @@ do_atof_calc:
if( esign<0 ){
result = 0.0*s;
}else{
+#ifdef INFINITY
+ result = INFINITY*s;
+#else
result = 1e308*1e308*s; /* Infinity */
+#endif
}
}
}else{
@@ -28770,16 +28712,12 @@ static int compare2pow63(const char *zNum, int incr){
** Convert zNum to a 64-bit signed integer. zNum must be decimal. This
** routine does *not* accept hexadecimal notation.
**
-** If the zNum value is representable as a 64-bit twos-complement
-** integer, then write that value into *pNum and return 0.
-**
-** If zNum is exactly 9223372036854775808, return 2. This special
-** case is broken out because while 9223372036854775808 cannot be a
-** signed 64-bit integer, its negative -9223372036854775808 can be.
+** Returns:
**
-** If zNum is too big for a 64-bit integer and is not
-** 9223372036854775808 or if zNum contains any non-numeric text,
-** then return 1.
+** 0 Successful transformation. Fits in a 64-bit signed integer.
+** 1 Excess text after the integer value
+** 2 Integer too large for a 64-bit signed integer or is malformed
+** 3 Special case of 9223372036854775808
**
** length is the number of bytes in the string (bytes, not characters).
** The string is not necessarily zero-terminated. The encoding is
@@ -28792,6 +28730,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
int i;
int c = 0;
int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
+ int rc; /* Baseline return code */
const char *zStart;
const char *zEnd = zNum + length;
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
@@ -28831,31 +28770,35 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
testcase( i==20 );
if( &zNum[i]<zEnd /* Extra bytes at the end */
|| (i==0 && zStart==zNum) /* No digits */
- || i>19*incr /* Too many digits */
|| nonNum /* UTF16 with high-order bytes non-zero */
){
+ rc = 1;
+ }else{
+ rc = 0;
+ }
+ if( i>19*incr ){ /* Too many digits */
/* zNum is empty or contains non-numeric text or is longer
** than 19 digits (thus guaranteeing that it is too large) */
- return 1;
+ return 2;
}else if( i<19*incr ){
/* Less than 19 digits, so we know that it fits in 64 bits */
assert( u<=LARGEST_INT64 );
- return 0;
+ return rc;
}else{
/* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
c = compare2pow63(zNum, incr);
if( c<0 ){
/* zNum is less than 9223372036854775808 so it fits */
assert( u<=LARGEST_INT64 );
- return 0;
+ return rc;
}else if( c>0 ){
/* zNum is greater than 9223372036854775808 so it overflows */
- return 1;
+ return 2;
}else{
/* zNum is exactly 9223372036854775808. Fits if negative. The
** special case 2 overflow if positive */
assert( u-1==LARGEST_INT64 );
- return neg ? 0 : 2;
+ return neg ? rc : 3;
}
}
}
@@ -28868,8 +28811,9 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
** Returns:
**
** 0 Successful transformation. Fits in a 64-bit signed integer.
-** 1 Integer too large for a 64-bit signed integer or is malformed
-** 2 Special case of 9223372036854775808
+** 1 Excess text after the integer value
+** 2 Integer too large for a 64-bit signed integer or is malformed
+** 3 Special case of 9223372036854775808
*/
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
#ifndef SQLITE_OMIT_HEX_INTEGER
@@ -28883,7 +28827,7 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
u = u*16 + sqlite3HexToInt(z[k]);
}
memcpy(pOut, &u, 8);
- return (z[k]==0 && k-i<=16) ? 0 : 1;
+ return (z[k]==0 && k-i<=16) ? 0 : 2;
}else
#endif /* SQLITE_OMIT_HEX_INTEGER */
{
@@ -29493,7 +29437,7 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
** overflow, leave *pA unchanged and return 1.
*/
SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
-#if GCC_VERSION>=5004000
+#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
return __builtin_add_overflow(*pA, iB, pA);
#else
i64 iA = *pA;
@@ -29513,7 +29457,7 @@ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
#endif
}
SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
-#if GCC_VERSION>=5004000
+#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
return __builtin_sub_overflow(*pA, iB, pA);
#else
testcase( iB==SMALLEST_INT64+1 );
@@ -29528,7 +29472,7 @@ SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
#endif
}
SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
-#if GCC_VERSION>=5004000
+#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
return __builtin_mul_overflow(*pA, iB, pA);
#else
i64 iA = *pA;
@@ -29630,8 +29574,14 @@ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){
if( x<2 ) return 0;
while( x<8 ){ y -= 10; x <<= 1; }
}else{
+#if GCC_VERSION>=5004000
+ int i = 60 - __builtin_clzll(x);
+ y += i*10;
+ x >>= i;
+#else
while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/
while( x>15 ){ y += 10; x >>= 1; }
+#endif
}
return a[x&7] + y - 10;
}
@@ -30112,47 +30062,47 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 40 */ "IdxLT" OpHelp("key=r[P3@P4]"),
/* 41 */ "IdxGE" OpHelp("key=r[P3@P4]"),
/* 42 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
- /* 43 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
- /* 44 */ "Program" OpHelp(""),
- /* 45 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
- /* 46 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
- /* 47 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
- /* 48 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
- /* 49 */ "IncrVacuum" OpHelp(""),
- /* 50 */ "VNext" OpHelp(""),
- /* 51 */ "Init" OpHelp("Start at P2"),
- /* 52 */ "Return" OpHelp(""),
- /* 53 */ "EndCoroutine" OpHelp(""),
- /* 54 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
- /* 55 */ "Halt" OpHelp(""),
- /* 56 */ "Integer" OpHelp("r[P2]=P1"),
- /* 57 */ "Int64" OpHelp("r[P2]=P4"),
- /* 58 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
- /* 59 */ "Null" OpHelp("r[P2..P3]=NULL"),
- /* 60 */ "SoftNull" OpHelp("r[P1]=NULL"),
- /* 61 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
- /* 62 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
- /* 63 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
- /* 64 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
- /* 65 */ "SCopy" OpHelp("r[P2]=r[P1]"),
- /* 66 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
- /* 67 */ "ResultRow" OpHelp("output=r[P1@P2]"),
- /* 68 */ "CollSeq" OpHelp(""),
- /* 69 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
- /* 70 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
- /* 71 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
- /* 72 */ "RealAffinity" OpHelp(""),
- /* 73 */ "Cast" OpHelp("affinity(r[P1])"),
- /* 74 */ "Permutation" OpHelp(""),
- /* 75 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
- /* 76 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
- /* 77 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
- /* 78 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
- /* 79 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
- /* 80 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
- /* 81 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
- /* 82 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
- /* 83 */ "ElseNotEq" OpHelp(""),
+ /* 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"),
+ /* 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]"),
+ /* 53 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
+ /* 54 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
+ /* 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 */ "Return" OpHelp(""),
+ /* 64 */ "EndCoroutine" OpHelp(""),
+ /* 65 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
+ /* 66 */ "Halt" OpHelp(""),
+ /* 67 */ "Integer" OpHelp("r[P2]=P1"),
+ /* 68 */ "Int64" OpHelp("r[P2]=P4"),
+ /* 69 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
+ /* 70 */ "Null" OpHelp("r[P2..P3]=NULL"),
+ /* 71 */ "SoftNull" OpHelp("r[P1]=NULL"),
+ /* 72 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
+ /* 73 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
+ /* 74 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
+ /* 75 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
+ /* 76 */ "SCopy" OpHelp("r[P2]=r[P1]"),
+ /* 77 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
+ /* 78 */ "ResultRow" OpHelp("output=r[P1@P2]"),
+ /* 79 */ "CollSeq" OpHelp(""),
+ /* 80 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
+ /* 81 */ "RealAffinity" OpHelp(""),
+ /* 82 */ "Cast" OpHelp("affinity(r[P1])"),
+ /* 83 */ "Permutation" OpHelp(""),
/* 84 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
/* 85 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
/* 86 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
@@ -30194,17 +30144,17 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 122 */ "RowData" OpHelp("r[P2]=data"),
/* 123 */ "Rowid" OpHelp("r[P2]=rowid"),
/* 124 */ "NullRow" OpHelp(""),
- /* 125 */ "SorterInsert" OpHelp("key=r[P2]"),
- /* 126 */ "IdxInsert" OpHelp("key=r[P2]"),
- /* 127 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
- /* 128 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"),
- /* 129 */ "IdxRowid" OpHelp("r[P2]=rowid"),
- /* 130 */ "Destroy" OpHelp(""),
- /* 131 */ "Clear" OpHelp(""),
+ /* 125 */ "SeekEnd" OpHelp(""),
+ /* 126 */ "SorterInsert" OpHelp("key=r[P2]"),
+ /* 127 */ "IdxInsert" OpHelp("key=r[P2]"),
+ /* 128 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
+ /* 129 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"),
+ /* 130 */ "IdxRowid" OpHelp("r[P2]=rowid"),
+ /* 131 */ "Destroy" OpHelp(""),
/* 132 */ "Real" OpHelp("r[P2]=P4"),
- /* 133 */ "ResetSorter" OpHelp(""),
- /* 134 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
- /* 135 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
+ /* 133 */ "Clear" OpHelp(""),
+ /* 134 */ "ResetSorter" OpHelp(""),
+ /* 135 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"),
/* 136 */ "SqlExec" OpHelp(""),
/* 137 */ "ParseSchema" OpHelp(""),
/* 138 */ "LoadAnalysis" OpHelp(""),
@@ -30336,6 +30286,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <sys/ioctl.h>
#include <unistd.h>
/* #include <time.h> */
#include <sys/time.h>
@@ -30345,7 +30296,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
-# include <sys/ioctl.h>
+/* # include <sys/ioctl.h> */
# include <sys/file.h>
# include <sys/param.h>
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
@@ -30455,7 +30406,7 @@ struct unixFile {
unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
int lastErrno; /* The unix errno from last I/O error */
void *lockingContext; /* Locking style specific state */
- UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
+ UnixUnusedFd *pPreallocatedUnused; /* Pre-allocated UnixUnusedFd */
const char *zPath; /* Name of the file */
unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
@@ -30466,10 +30417,8 @@ struct unixFile {
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
void *pMapRegion; /* Memory mapped region */
#endif
-#ifdef __QNXNTO__
int sectorSize; /* Device sector size */
int deviceCharacteristics; /* Precomputed device characteristics */
-#endif
#if SQLITE_ENABLE_LOCKING_STYLE
int openFlags; /* The flags specified at open() */
#endif
@@ -30772,6 +30721,20 @@ SQLITE_API extern int sqlite3_open_file_count;
# define lseek lseek64
#endif
+#ifdef __linux__
+/*
+** Linux-specific IOCTL magic numbers used for controlling F2FS
+*/
+#define F2FS_IOCTL_MAGIC 0xf5
+#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1)
+#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2)
+#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3)
+#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
+#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32)
+#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
+#endif /* __linux__ */
+
+
/*
** Different Unix systems declare open() in different ways. Same use
** open(const char*,int,mode_t). Others use open(const char*,int,...).
@@ -30944,6 +30907,9 @@ static struct unix_syscall {
#endif
#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
+ { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 },
+#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent)
+
}; /* End of the overrideable system calls */
@@ -31548,7 +31514,8 @@ struct unixInodeInfo {
/*
** A lists of all unixInodeInfo objects.
*/
-static unixInodeInfo *inodeList = 0;
+static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */
+static unsigned int nUnusedFd = 0; /* Total unused file descriptors */
/*
**
@@ -31658,6 +31625,7 @@ static void closePendingFds(unixFile *pFile){
pNext = p->pNext;
robust_close(pFile, p->fd, __LINE__);
sqlite3_free(p);
+ nUnusedFd--;
}
pInode->pUnused = 0;
}
@@ -31690,6 +31658,7 @@ static void releaseInodeInfo(unixFile *pFile){
sqlite3_free(pInode);
}
}
+ assert( inodeList!=0 || nUnusedFd==0 );
}
/*
@@ -31759,6 +31728,7 @@ static int findInodeInfo(
#else
fileId.ino = (u64)statbuf.st_ino;
#endif
+ assert( inodeList!=0 || nUnusedFd==0 );
pInode = inodeList;
while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
pInode = pInode->pNext;
@@ -32184,11 +32154,12 @@ end_lock:
*/
static void setPendingFd(unixFile *pFile){
unixInodeInfo *pInode = pFile->pInode;
- UnixUnusedFd *p = pFile->pUnused;
+ UnixUnusedFd *p = pFile->pPreallocatedUnused;
p->pNext = pInode->pUnused;
pInode->pUnused = p;
pFile->h = -1;
- pFile->pUnused = 0;
+ pFile->pPreallocatedUnused = 0;
+ nUnusedFd++;
}
/*
@@ -32413,7 +32384,7 @@ static int closeUnixFile(sqlite3_file *id){
#endif
OSTRACE(("CLOSE %-3d\n", pFile->h));
OpenCounter(-1);
- sqlite3_free(pFile->pUnused);
+ sqlite3_free(pFile->pPreallocatedUnused);
memset(pFile, 0, sizeof(unixFile));
return SQLITE_OK;
}
@@ -32750,7 +32721,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
+ if( (rc & 0xff) == SQLITE_IOERR ){
rc = SQLITE_OK;
reserved=1;
}
@@ -32817,7 +32788,7 @@ static int flockLock(sqlite3_file *id, int 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 & SQLITE_IOERR) == SQLITE_IOERR ){
+ if( (rc & 0xff) == SQLITE_IOERR ){
rc = SQLITE_BUSY;
}
#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
@@ -33354,7 +33325,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
/* Can't reestablish the shared lock. Sqlite can't deal, this is
** a critical I/O error
*/
- rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 :
+ rc = ((failed & 0xff) == SQLITE_IOERR) ? failed2 :
SQLITE_IOERR_LOCK;
goto afp_end_lock;
}
@@ -33634,7 +33605,7 @@ static int unixRead(
/* If this is a database file (not a journal, master-journal or temp
** file), the bytes in the locking range should never be read or written. */
#if 0
- assert( pFile->pUnused==0
+ assert( pFile->pPreallocatedUnused==0
|| offset>=PENDING_BYTE+512
|| offset+amt<=PENDING_BYTE
);
@@ -33747,7 +33718,7 @@ static int unixWrite(
/* If this is a database file (not a journal, master-journal or temp
** file), the bytes in the locking range should never be read or written. */
#if 0
- assert( pFile->pUnused==0
+ assert( pFile->pPreallocatedUnused==0
|| offset>=PENDING_BYTE+512
|| offset+amt<=PENDING_BYTE
);
@@ -34227,6 +34198,21 @@ static int unixGetTempname(int nBuf, char *zBuf);
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
unixFile *pFile = (unixFile*)id;
switch( op ){
+#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+ case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: {
+ int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE);
+ return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK;
+ }
+ case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: {
+ int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE);
+ return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK;
+ }
+ case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
+ int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
+ return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK;
+ }
+#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
+
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = pFile->eFileLock;
return SQLITE_OK;
@@ -34277,6 +34263,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
if( newLimit>sqlite3GlobalConfig.mxMmap ){
newLimit = sqlite3GlobalConfig.mxMmap;
}
+
+ /* The value of newLimit may be eventually cast to (size_t) and passed
+ ** to mmap(). Restrict its value to 2GB if (size_t) is not at least a
+ ** 64-bit type. */
+ if( newLimit>0 && sizeof(size_t)<8 ){
+ newLimit = (newLimit & 0x7FFFFFFF);
+ }
+
*(i64*)pArg = pFile->mmapSizeMax;
if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
pFile->mmapSizeMax = newLimit;
@@ -34310,30 +34304,41 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
/*
-** Return the sector size in bytes of the underlying block device for
-** the specified file. This is almost always 512 bytes, but may be
-** larger for some devices.
+** 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.
**
-** SQLite code assumes this function cannot fail. It also assumes that
-** if two files are created in the same file-system directory (i.e.
-** a database and its journal file) that the sector size will be the
-** same for both.
+** There are two versions of this function. One for QNX and one for all
+** other systems.
*/
#ifndef __QNXNTO__
-static int unixSectorSize(sqlite3_file *NotUsed){
- UNUSED_PARAMETER(NotUsed);
- return SQLITE_DEFAULT_SECTOR_SIZE;
-}
-#endif
+static void setDeviceCharacteristics(unixFile *pFd){
+ assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 );
+ if( pFd->sectorSize==0 ){
+#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+ int res;
+ u32 f = 0;
-/*
-** The following version of unixSectorSize() is optimized for QNX.
-*/
-#ifdef __QNXNTO__
+ /* Check for support for F2FS atomic batch writes. */
+ res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f);
+ if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){
+ pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC;
+ }
+#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
+
+ /* Set the POWERSAFE_OVERWRITE flag if requested. */
+ if( pFd->ctrlFlags & UNIXFILE_PSOW ){
+ pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
+ }
+
+ pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
+ }
+}
+#else
#include <sys/dcmd_blk.h>
#include <sys/statvfs.h>
-static int unixSectorSize(sqlite3_file *id){
- unixFile *pFile = (unixFile*)id;
+static void setDeviceCharacteristics(unixFile *pFile){
if( pFile->sectorSize == 0 ){
struct statvfs fsInfo;
@@ -34402,9 +34407,24 @@ static int unixSectorSize(sqlite3_file *id){
pFile->deviceCharacteristics = 0;
pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
}
- return pFile->sectorSize;
}
-#endif /* __QNXNTO__ */
+#endif
+
+/*
+** Return the sector size in bytes of the underlying block device for
+** the specified file. This is almost always 512 bytes, but may be
+** larger for some devices.
+**
+** SQLite code assumes this function cannot fail. It also assumes that
+** if two files are created in the same file-system directory (i.e.
+** a database and its journal file) that the sector size will be the
+** same for both.
+*/
+static int unixSectorSize(sqlite3_file *id){
+ unixFile *pFd = (unixFile*)id;
+ setDeviceCharacteristics(pFd);
+ return pFd->sectorSize;
+}
/*
** Return the device characteristics for the file.
@@ -34420,16 +34440,9 @@ static int unixSectorSize(sqlite3_file *id){
** available to turn it off and URI query parameter available to turn it off.
*/
static int unixDeviceCharacteristics(sqlite3_file *id){
- unixFile *p = (unixFile*)id;
- int rc = 0;
-#ifdef __QNXNTO__
- if( p->sectorSize==0 ) unixSectorSize(id);
- rc = p->deviceCharacteristics;
-#endif
- if( p->ctrlFlags & UNIXFILE_PSOW ){
- rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
- }
- return rc;
+ unixFile *pFd = (unixFile*)id;
+ setDeviceCharacteristics(pFd);
+ return pFd->deviceCharacteristics;
}
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
@@ -35687,17 +35700,6 @@ static int fillInUnixFile(
assert( pNew->pInode==NULL );
- /* Usually the path zFilename should not be a relative pathname. The
- ** exception is when opening the proxy "conch" file in builds that
- ** include the special Apple locking styles.
- */
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- assert( zFilename==0 || zFilename[0]=='/'
- || pVfs->pAppData==(void*)&autolockIoFinder );
-#else
- assert( zFilename==0 || zFilename[0]=='/' );
-#endif
-
/* No locking occurs in temporary files */
assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 );
@@ -35956,6 +35958,8 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
#if !OS_VXWORKS
struct stat sStat; /* Results of stat() call */
+ unixEnterMutex();
+
/* A stat() call may fail for various reasons. If this happens, it is
** almost certain that an open() call on the same path will also fail.
** For this reason, if an error occurs in the stat() call here, it is
@@ -35964,10 +35968,9 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
**
** Even if a subsequent open() call does succeed, the consequences of
** not searching for a reusable file descriptor are not dire. */
- if( 0==osStat(zPath, &sStat) ){
+ if( nUnusedFd>0 && 0==osStat(zPath, &sStat) ){
unixInodeInfo *pInode;
- unixEnterMutex();
pInode = inodeList;
while( pInode && (pInode->fileId.dev!=sStat.st_dev
|| pInode->fileId.ino!=(u64)sStat.st_ino) ){
@@ -35978,11 +35981,12 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
pUnused = *pp;
if( pUnused ){
+ nUnusedFd--;
*pp = pUnused->pNext;
}
}
- unixLeaveMutex();
}
+ unixLeaveMutex();
#endif /* if !OS_VXWORKS */
return pUnused;
}
@@ -36058,16 +36062,11 @@ static int findCreateFileMode(
*/
nDb = sqlite3Strlen30(zPath) - 1;
while( zPath[nDb]!='-' ){
-#ifndef SQLITE_ENABLE_8_3_NAMES
- /* In the normal case (8+3 filenames disabled) the journal filename
- ** is guaranteed to contain a '-' character. */
- assert( nDb>0 );
- assert( sqlite3Isalnum(zPath[nDb]) );
-#else
- /* If 8+3 names are possible, then the journal file might not contain
- ** a '-' character. So check for that case and return early. */
+ /* 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;
-#endif
nDb--;
}
memcpy(zDb, zPath, nDb);
@@ -36109,20 +36108,21 @@ int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
memset(p, 0, sizeof(unixFile));
/* osStat() will not work in the sandbox, so findReusableFd() will always
- ** fail, so directly include the failure-case setup then initialize pUnused.
+ ** fail, so directly include the failure-case setup then initialize
+ ** pPreallocatedUnused.
*/
if( eType==SQLITE_OPEN_MAIN_DB ){
- p->pUnused = sqlite3_malloc(sizeof(*p->pUnused));
- if (!p->pUnused) {
+ p->pPreallocatedUnused = sqlite3_malloc(sizeof(*p->pPreallocatedUnused));
+ if (!p->pPreallocatedUnused) {
return SQLITE_NOMEM_BKPT;
}
- p->pUnused->fd = fd;
- p->pUnused->flags = flags;
+ p->pPreallocatedUnused->fd = fd;
+ p->pPreallocatedUnused->flags = flags;
}
rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
if( rc!=SQLITE_OK ){
- sqlite3_free(p->pUnused);
+ sqlite3_free(p->pPreallocatedUnused);
}
return rc;
}
@@ -36243,7 +36243,7 @@ static int unixOpen(
return SQLITE_NOMEM_BKPT;
}
}
- p->pUnused = pUnused;
+ p->pPreallocatedUnused = pUnused;
/* Database filenames are double-zero terminated if they are not
** URIs with parameters. Hence, they can always be passed into
@@ -36280,7 +36280,7 @@ static int unixOpen(
gid_t gid; /* Groupid for the file */
rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
if( rc!=SQLITE_OK ){
- assert( !p->pUnused );
+ assert( !p->pPreallocatedUnused );
assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
return rc;
}
@@ -36314,10 +36314,10 @@ static int unixOpen(
*pOutFlags = flags;
}
- if( p->pUnused ){
+ if( p->pPreallocatedUnused ){
/* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
- p->pUnused->fd = fd;
- p->pUnused->flags = flags;
+ p->pPreallocatedUnused->fd = fd;
+ p->pPreallocatedUnused->flags = flags;
}
if( isDelete ){
@@ -36394,13 +36394,16 @@ static int unixOpen(
}
#endif
+ assert( zPath==0 || zPath[0]=='/'
+ || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
+ );
/* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
open_finished:
if( rc!=SQLITE_OK ){
/* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
- sqlite3_free(p->pUnused);
+ sqlite3_free(p->pPreallocatedUnused);
}
return rc;
}
@@ -37141,7 +37144,7 @@ static int proxyCreateUnixFile(
dummyVfs.zName = "dummy";
pUnused->fd = fd;
pUnused->flags = openFlags;
- pNew->pUnused = pUnused;
+ pNew->pPreallocatedUnused = pUnused;
rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0);
if( rc==SQLITE_OK ){
@@ -38091,7 +38094,7 @@ SQLITE_API int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==28 );
+ assert( ArraySize(aSyscall)==29 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
@@ -41874,6 +41877,14 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
if( newLimit>sqlite3GlobalConfig.mxMmap ){
newLimit = sqlite3GlobalConfig.mxMmap;
}
+
+ /* The value of newLimit may be eventually cast to (SIZE_T) and passed
+ ** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at
+ ** least a 64-bit type. */
+ if( newLimit>0 && sizeof(SIZE_T)<8 ){
+ newLimit = (newLimit & 0x7FFFFFFF);
+ }
+
*(i64*)pArg = pFile->mmapSizeMax;
if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
pFile->mmapSizeMax = newLimit;
@@ -43186,6 +43197,14 @@ static int winIsDir(const void *zConverted){
return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
}
+/* forward reference */
+static int winAccess(
+ sqlite3_vfs *pVfs, /* Not used on win32 */
+ const char *zFilename, /* Name of file to check */
+ int flags, /* Type of test to make on this file */
+ int *pResOut /* OUT: Result */
+);
+
/*
** Open a file.
*/
@@ -43362,37 +43381,52 @@ static int winOpen(
extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
extendedParameters.lpSecurityAttributes = NULL;
extendedParameters.hTemplateFile = NULL;
- while( (h = osCreateFile2((LPCWSTR)zConverted,
- dwDesiredAccess,
- dwShareMode,
- dwCreationDisposition,
- &extendedParameters))==INVALID_HANDLE_VALUE &&
- winRetryIoerr(&cnt, &lastErrno) ){
- /* Noop */
- }
+ do{
+ h = osCreateFile2((LPCWSTR)zConverted,
+ dwDesiredAccess,
+ dwShareMode,
+ dwCreationDisposition,
+ &extendedParameters);
+ if( h!=INVALID_HANDLE_VALUE ) break;
+ if( isReadWrite ){
+ int isRO = 0;
+ int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ if( rc2==SQLITE_OK && isRO ) break;
+ }
+ }while( winRetryIoerr(&cnt, &lastErrno) );
#else
- while( (h = osCreateFileW((LPCWSTR)zConverted,
- dwDesiredAccess,
- dwShareMode, NULL,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- NULL))==INVALID_HANDLE_VALUE &&
- winRetryIoerr(&cnt, &lastErrno) ){
- /* Noop */
- }
+ do{
+ h = osCreateFileW((LPCWSTR)zConverted,
+ dwDesiredAccess,
+ dwShareMode, NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL);
+ if( h!=INVALID_HANDLE_VALUE ) break;
+ if( isReadWrite ){
+ int isRO = 0;
+ int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ if( rc2==SQLITE_OK && isRO ) break;
+ }
+ }while( winRetryIoerr(&cnt, &lastErrno) );
#endif
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
- while( (h = osCreateFileA((LPCSTR)zConverted,
- dwDesiredAccess,
- dwShareMode, NULL,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- NULL))==INVALID_HANDLE_VALUE &&
- winRetryIoerr(&cnt, &lastErrno) ){
- /* Noop */
- }
+ do{
+ h = osCreateFileA((LPCSTR)zConverted,
+ dwDesiredAccess,
+ dwShareMode, NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL);
+ if( h!=INVALID_HANDLE_VALUE ) break;
+ if( isReadWrite ){
+ int isRO = 0;
+ int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ if( rc2==SQLITE_OK && isRO ) break;
+ }
+ }while( winRetryIoerr(&cnt, &lastErrno) );
}
#endif
winLogIoerr(cnt, __LINE__);
@@ -43401,8 +43435,6 @@ static int winOpen(
dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
if( h==INVALID_HANDLE_VALUE ){
- pFile->lastErrno = lastErrno;
- winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
sqlite3_free(zConverted);
sqlite3_free(zTmpname);
if( isReadWrite && !isExclusive ){
@@ -43411,6 +43443,8 @@ static int winOpen(
~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
pOutFlags);
}else{
+ pFile->lastErrno = lastErrno;
+ winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
return SQLITE_CANTOPEN_BKPT;
}
}
@@ -44003,9 +44037,6 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
EntropyGatherer e;
UNUSED_PARAMETER(pVfs);
memset(zBuf, 0, nBuf);
-#if defined(_MSC_VER) && _MSC_VER>=1400 && !SQLITE_OS_WINCE
- rand_s((unsigned int*)zBuf); /* rand_s() is not available with MinGW */
-#endif /* defined(_MSC_VER) && _MSC_VER>=1400 */
e.a = (unsigned char*)zBuf;
e.na = nBuf;
e.nXor = 0;
@@ -44932,12 +44963,9 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
p->eCreate = 2;
}
}
- pPage->pDirtyNext = 0;
- pPage->pDirtyPrev = 0;
}
if( addRemove & PCACHE_DIRTYLIST_ADD ){
- assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
-
+ pPage->pDirtyPrev = 0;
pPage->pDirtyNext = p->pDirty;
if( pPage->pDirtyNext ){
assert( pPage->pDirtyNext->pDirtyPrev==0 );
@@ -45254,11 +45282,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
if( (--p->nRef)==0 ){
if( p->flags&PGHDR_CLEAN ){
pcacheUnpin(p);
- }else if( p->pDirtyPrev!=0 ){ /*OPTIMIZATION-IF-FALSE*/
- /* Move the page to the head of the dirty list. If p->pDirtyPrev==0,
- ** then page p is already at the head of the dirty list and the
- ** following call would be a no-op. Hence the OPTIMIZATION-IF-FALSE
- ** tag above. */
+ }else{
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
@@ -45719,7 +45743,6 @@ typedef struct PGroup PGroup;
struct PgHdr1 {
sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
unsigned int iKey; /* Key value (page number) */
- u8 isPinned; /* Page in use, not on the LRU list */
u8 isBulkLocal; /* This page from bulk local storage */
u8 isAnchor; /* This is the PGroup.lru element */
PgHdr1 *pNext; /* Next in hash table chain */
@@ -45728,6 +45751,12 @@ struct PgHdr1 {
PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
};
+/*
+** A page is pinned if it is no on the LRU list
+*/
+#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
** 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
@@ -45755,7 +45784,7 @@ struct PGroup {
unsigned int nMaxPage; /* Sum of nMax for purgeable caches */
unsigned int nMinPage; /* Sum of nMin for purgeable caches */
unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */
- unsigned int nCurrentPage; /* Number of purgeable pages allocated */
+ unsigned int nPurgeable; /* Number of purgeable pages allocated */
PgHdr1 lru; /* The beginning and end of the LRU list */
};
@@ -45769,11 +45798,13 @@ struct PGroup {
*/
struct PCache1 {
/* Cache configuration parameters. Page size (szPage) and the purgeable
- ** flag (bPurgeable) are set when the cache is created. nMax may be
+ ** flag (bPurgeable) and the pnPurgeable pointer are all set when the
+ ** 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.
*/
PGroup *pGroup; /* PGroup this cache belongs to */
+ unsigned int *pnPurgeable; /* Pointer to pGroup->nPurgeable */
int szPage; /* Size of database content section */
int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */
int szAlloc; /* Total size of one pcache line */
@@ -45868,6 +45899,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
if( pcache1.isInit ){
PgFreeslot *p;
if( pBuf==0 ) sz = n = 0;
+ if( n==0 ) sz = 0;
sz = ROUNDDOWN8(sz);
pcache1.szSlot = sz;
pcache1.nSlot = pcache1.nFreeSlot = n;
@@ -46060,9 +46092,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
p->isBulkLocal = 0;
p->isAnchor = 0;
}
- if( pCache->bPurgeable ){
- pCache->pGroup->nCurrentPage++;
- }
+ (*pCache->pnPurgeable)++;
return p;
}
@@ -46083,9 +46113,7 @@ static void pcache1FreePage(PgHdr1 *p){
sqlite3_free(p);
#endif
}
- if( pCache->bPurgeable ){
- pCache->pGroup->nCurrentPage--;
- }
+ (*pCache->pnPurgeable)--;
}
/*
@@ -46180,22 +46208,18 @@ static void pcache1ResizeHash(PCache1 *p){
** The PGroup mutex must be held when this function is called.
*/
static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
- PCache1 *pCache;
-
assert( pPage!=0 );
- assert( pPage->isPinned==0 );
- pCache = pPage->pCache;
+ assert( PAGE_IS_UNPINNED(pPage) );
assert( pPage->pLruNext );
assert( pPage->pLruPrev );
- assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
+ assert( sqlite3_mutex_held(pPage->pCache->pGroup->mutex) );
pPage->pLruPrev->pLruNext = pPage->pLruNext;
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
pPage->pLruNext = 0;
pPage->pLruPrev = 0;
- pPage->isPinned = 1;
assert( pPage->isAnchor==0 );
- assert( pCache->pGroup->lru.isAnchor==1 );
- pCache->nRecyclable--;
+ assert( pPage->pCache->pGroup->lru.isAnchor==1 );
+ pPage->pCache->nRecyclable--;
return pPage;
}
@@ -46229,11 +46253,11 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){
PGroup *pGroup = pCache->pGroup;
PgHdr1 *p;
assert( sqlite3_mutex_held(pGroup->mutex) );
- while( pGroup->nCurrentPage>pGroup->nMaxPage
+ while( pGroup->nPurgeable>pGroup->nMaxPage
&& (p=pGroup->lru.pLruPrev)->isAnchor==0
){
assert( p->pCache->pGroup==pGroup );
- assert( p->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
}
@@ -46282,7 +46306,7 @@ static void pcache1TruncateUnsafe(
if( pPage->iKey>=iLimit ){
pCache->nPage--;
*pp = pPage->pNext;
- if( !pPage->isPinned ) pcache1PinPage(pPage);
+ if( PAGE_IS_UNPINNED(pPage) ) pcache1PinPage(pPage);
pcache1FreePage(pPage);
}else{
pp = &pPage->pNext;
@@ -46404,6 +46428,10 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
pCache->nMin = 10;
pGroup->nMinPage += pCache->nMin;
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
+ pCache->pnPurgeable = &pGroup->nPurgeable;
+ }else{
+ static unsigned int dummyCurrentPage;
+ pCache->pnPurgeable = &dummyCurrentPage;
}
pcache1LeaveMutex(pGroup);
if( pCache->nHash==0 ){
@@ -46505,7 +46533,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
){
PCache1 *pOther;
pPage = pGroup->lru.pLruPrev;
- assert( pPage->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(pPage) );
pcache1RemoveFromHash(pPage, 0);
pcache1PinPage(pPage);
pOther = pPage->pCache;
@@ -46513,7 +46541,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
pcache1FreePage(pPage);
pPage = 0;
}else{
- pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
+ pGroup->nPurgeable -= (pOther->bPurgeable - pCache->bPurgeable);
}
}
@@ -46532,7 +46560,6 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
pPage->pCache = pCache;
pPage->pLruPrev = 0;
pPage->pLruNext = 0;
- pPage->isPinned = 1;
*(void **)pPage->page.pExtra = 0;
pCache->apHash[h] = pPage;
if( iKey>pCache->iMaxKey ){
@@ -46618,7 +46645,7 @@ static PgHdr1 *pcache1FetchNoMutex(
** Otherwise (page not in hash and createFlag!=0) continue with
** subsequent steps to try to create the page. */
if( pPage ){
- if( !pPage->isPinned ){
+ if( PAGE_IS_UNPINNED(pPage) ){
return pcache1PinPage(pPage);
}else{
return pPage;
@@ -46693,9 +46720,9 @@ static void pcache1Unpin(
** part of the PGroup LRU list.
*/
assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
- assert( pPage->isPinned==1 );
+ assert( PAGE_IS_PINNED(pPage) );
- if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
+ if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){
pcache1RemoveFromHash(pPage, 1);
}else{
/* Add the page to the PGroup LRU list. */
@@ -46704,7 +46731,6 @@ static void pcache1Unpin(
(pPage->pLruNext = *ppFirst)->pLruPrev = pPage;
*ppFirst = pPage;
pCache->nRecyclable++;
- pPage->isPinned = 0;
}
pcache1LeaveMutex(pCache->pGroup);
@@ -46848,7 +46874,7 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
nFree += sqlite3MemSize(p);
#endif
- assert( p->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
}
@@ -46872,10 +46898,10 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
PgHdr1 *p;
int nRecyclable = 0;
for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){
- assert( p->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(p) );
nRecyclable++;
}
- *pnCurrent = pcache1.grp.nCurrentPage;
+ *pnCurrent = pcache1.grp.nPurgeable;
*pnMax = (int)pcache1.grp.nMaxPage;
*pnMin = (int)pcache1.grp.nMinPage;
*pnRecyclable = nRecyclable;
@@ -47430,11 +47456,11 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
/* #include "sqliteInt.h" */
-/* Additional values that can be added to the sync_flags argument of
-** sqlite3WalFrames():
+/* Macros for extracting appropriate sync flags for either transaction
+** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)):
*/
-#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */
-#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */
+#define WAL_SYNC_FLAGS(X) ((X)&0x03)
+#define CKPT_SYNC_FLAGS(X) (((X)>>2)&0x03)
#ifdef SQLITE_OMIT_WAL
# define sqlite3WalOpen(x,y,z) 0
@@ -47667,8 +47693,8 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
** struct as its argument.
*/
-#define PAGERID(p) ((int)(p->fd))
-#define FILEHANDLEID(fd) ((int)fd)
+#define PAGERID(p) (SQLITE_PTR_TO_INT(p->fd))
+#define FILEHANDLEID(fd) (SQLITE_PTR_TO_INT(fd))
/*
** The Pager.eState variable stores the current 'state' of a pager. A
@@ -48155,6 +48181,18 @@ struct PagerSavepoint {
** 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
+**
+** syncFlags is either SQLITE_SYNC_NORMAL (0x02) or SQLITE_SYNC_FULL (0x03).
+** syncFlags is used for rollback mode. walSyncFlags is used for WAL mode
+** and contains the flags used to sync the checkpoint operations in the
+** lower two bits, and sync flags used for transaction commits in the WAL
+** file in bits 0x04 and 0x08. In other words, to get the correct sync flags
+** for checkpoint operations, use (walSyncFlags&0x03) and to get the correct
+** sync flags for transaction commit, use ((walSyncFlags>>2)&0x03). Note
+** that with synchronous=NORMAL in WAL mode, transaction commit is not synced
+** meaning that the 0x04 and 0x08 bits are both zero.
*/
struct Pager {
sqlite3_vfs *pVfs; /* OS functions to use for IO */
@@ -48164,9 +48202,8 @@ struct Pager {
u8 noSync; /* Do not sync the journal if true */
u8 fullSync; /* Do extra syncs of the journal for robustness */
u8 extraSync; /* sync directory after journal delete */
- u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */
- u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */
u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */
+ u8 walSyncFlags; /* See description above */
u8 tempFile; /* zFilename is a temporary or immutable file */
u8 noLock; /* Do not lock (except in WAL mode) */
u8 readOnly; /* True for a read-only database */
@@ -48486,6 +48523,7 @@ static int assert_pager_state(Pager *p){
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 );
break;
@@ -48497,6 +48535,7 @@ static int assert_pager_state(Pager *p){
assert( isOpen(p->jfd)
|| p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_WAL
+ || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
);
break;
@@ -48707,34 +48746,47 @@ static int pagerLockDb(Pager *pPager, int eLock){
}
/*
-** This function determines whether or not the atomic-write optimization
-** can be used with this pager. The optimization can be used if:
+** This function determines whether or not the atomic-write or
+** atomic-batch-write optimizations can be used with this pager. The
+** atomic-write optimization can be used if:
**
** (a) the value returned by OsDeviceCharacteristics() indicates that
** a database page may be written atomically, and
** (b) the value returned by OsSectorSize() is less than or equal
** to the page size.
**
-** The optimization is also always enabled for temporary files. It is
-** an error to call this function if pPager is opened on an in-memory
-** database.
+** 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.
**
-** If the optimization cannot be used, 0 is returned. 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()
+** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is
+** returned in this case.
+**
+** If neither optimization can be used, 0 is returned.
*/
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
static int jrnlBufferSize(Pager *pPager){
assert( !MEMDB );
- if( !pPager->tempFile ){
- int dc; /* Device characteristics */
- int nSector; /* Sector size */
- int szPage; /* Page size */
- assert( isOpen(pPager->fd) );
- dc = sqlite3OsDeviceCharacteristics(pPager->fd);
- nSector = pPager->sectorSize;
- szPage = pPager->pageSize;
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+ int dc; /* Device characteristics */
+
+ assert( isOpen(pPager->fd) );
+ dc = sqlite3OsDeviceCharacteristics(pPager->fd);
+#else
+ UNUSED_PARAMETER(pPager);
+#endif
+
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ if( dc&SQLITE_IOCAP_BATCH_ATOMIC ){
+ return -1;
+ }
+#endif
+
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ {
+ int nSector = pPager->sectorSize;
+ int szPage = pPager->pageSize;
assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
@@ -48744,11 +48796,11 @@ static int jrnlBufferSize(Pager *pPager){
}
return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
-}
-#else
-# define jrnlBufferSize(x) 0
#endif
+ return 0;
+}
+
/*
** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
** on the cache using a hash function. This is used for testing
@@ -48830,6 +48882,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
|| szJ<16
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
|| len>=nMaster
+ || len>szJ-16
|| len==0
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
|| SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
@@ -49551,7 +49604,9 @@ 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) ){
assert( !pagerUseWal(pPager) );
@@ -50319,6 +50374,7 @@ static int pager_playback(Pager *pPager, int isHot){
char *zMaster = 0; /* Name of master 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;
/* Figure out how many records are in the journal. Abort early if
** the journal is empty.
@@ -50448,6 +50504,9 @@ static int pager_playback(Pager *pPager, int isHot){
assert( 0 );
end_playback:
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerSetPagesize(pPager, &savedPageSize, -1);
+ }
/* Following a rollback, the database file should be back in its original
** state prior to the start of the transaction, so invoke the
** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the
@@ -50506,7 +50565,8 @@ end_playback:
/*
-** Read the content for page pPg out of the database file and into
+** 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
** pPg->pData. A shared lock or greater must be held on the database
** file before this function is called.
**
@@ -50516,30 +50576,33 @@ end_playback:
** If an IO error occurs, then the IO error is returned to the caller.
** Otherwise, SQLITE_OK is returned.
*/
-static int readDbPage(PgHdr *pPg, u32 iFrame){
+static int readDbPage(PgHdr *pPg){
Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
- Pgno pgno = pPg->pgno; /* Page number to read */
int rc = SQLITE_OK; /* Return code */
- int pgsz = pPager->pageSize; /* Number of bytes to read */
+
+#ifndef SQLITE_OMIT_WAL
+ u32 iFrame = 0; /* Frame of WAL containing pgno */
assert( pPager->eState>=PAGER_READER && !MEMDB );
assert( isOpen(pPager->fd) );
-#ifndef SQLITE_OMIT_WAL
+ if( pagerUseWal(pPager) ){
+ rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
+ if( rc ) return rc;
+ }
if( iFrame ){
- /* Try to pull the page from the write-ahead log. */
- rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
+ rc = sqlite3WalReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData);
}else
#endif
{
- i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
- rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
+ i64 iOffset = (pPg->pgno-1)*(i64)pPager->pageSize;
+ rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
}
- if( pgno==1 ){
+ if( pPg->pgno==1 ){
if( rc ){
/* If the read is unsuccessful, set the dbFileVers[] to something
** that will never be a valid file version. dbFileVers[] is a copy
@@ -50559,13 +50622,13 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
}
}
- CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM_BKPT);
+ 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, pgno));
+ IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno));
PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
- PAGERID(pPager), pgno, pager_pagehash(pPg)));
+ PAGERID(pPager), pPg->pgno, pager_pagehash(pPg)));
return rc;
}
@@ -50616,11 +50679,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
if( sqlite3PcachePageRefcount(pPg)==1 ){
sqlite3PcacheDrop(pPg);
}else{
- u32 iFrame = 0;
- rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
- if( rc==SQLITE_OK ){
- rc = readDbPage(pPg, iFrame);
- }
+ rc = readDbPage(pPg);
if( rc==SQLITE_OK ){
pPager->xReiniter(pPg);
}
@@ -51126,20 +51185,17 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags(
}
if( pPager->noSync ){
pPager->syncFlags = 0;
- pPager->ckptSyncFlags = 0;
}else if( pgFlags & PAGER_FULLFSYNC ){
pPager->syncFlags = SQLITE_SYNC_FULL;
- pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
- }else if( pgFlags & PAGER_CKPT_FULLFSYNC ){
- pPager->syncFlags = SQLITE_SYNC_NORMAL;
- pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
}else{
pPager->syncFlags = SQLITE_SYNC_NORMAL;
- pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
}
- pPager->walSyncFlags = pPager->syncFlags;
+ pPager->walSyncFlags = (pPager->syncFlags<<2);
if( pPager->fullSync ){
- pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
+ pPager->walSyncFlags |= pPager->syncFlags;
+ }
+ if( (pgFlags & PAGER_CKPT_FULLFSYNC) && !pPager->noSync ){
+ pPager->walSyncFlags |= (SQLITE_SYNC_FULL<<2);
}
if( pgFlags & PAGER_CACHESPILL ){
pPager->doNotSpill &= ~SPILLFLAG_OFF;
@@ -51638,7 +51694,7 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
assert( db || pPager->pWal==0 );
- sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags, pPager->pageSize,
+ sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,
(db && (db->flags & SQLITE_NoCkptOnClose) ? 0 : pTmp)
);
pPager->pWal = 0;
@@ -52107,6 +52163,13 @@ static int pagerStress(void *p, PgHdr *pPg){
}
}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
|| pPager->eState==PAGER_WRITER_CACHEMOD
@@ -52439,13 +52502,11 @@ act_like_temp_file:
assert( pPager->extraSync==0 );
assert( pPager->syncFlags==0 );
assert( pPager->walSyncFlags==0 );
- assert( pPager->ckptSyncFlags==0 );
}else{
pPager->fullSync = 1;
pPager->extraSync = 0;
pPager->syncFlags = SQLITE_SYNC_NORMAL;
- pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
- pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
+ pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2);
}
/* pPager->pFirst = 0; */
/* pPager->pFirstSynced = 0; */
@@ -52865,7 +52926,8 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
** nothing to rollback, so this routine is a no-op.
*/
static void pagerUnlockIfUnused(Pager *pPager){
- if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
+ if( sqlite3PcacheRefCount(pPager->pPCache)==0 ){
+ assert( pPager->nMmapOut==0 ); /* because page1 is never memory mapped */
pagerUnlockAndRollback(pPager);
}
}
@@ -53006,14 +53068,9 @@ static int getPageNormal(
memset(pPg->pData, 0, pPager->pageSize);
IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{
- u32 iFrame = 0; /* Frame to read from WAL file */
- if( pagerUseWal(pPager) ){
- rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
- if( rc!=SQLITE_OK ) goto pager_acquire_err;
- }
assert( pPg->pPager==pPager );
pPager->aStat[PAGER_STAT_MISS]++;
- rc = readDbPage(pPg, iFrame);
+ rc = readDbPage(pPg);
if( rc!=SQLITE_OK ){
goto pager_acquire_err;
}
@@ -53156,25 +53213,39 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
/*
** Release a page reference.
**
-** If the number of references to the page drop to zero, then the
-** page is added to the LRU list. When all references to all pages
-** are released, a rollback occurs and the lock on the database is
-** removed.
+** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be
+** used if we know that the page being released is not the last page.
+** The btree layer always holds page1 open until the end, so these first
+** to routines can be used to release any page other than BtShared.pPage1.
+**
+** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine
+** checks the total number of outstanding pages and if the number of
+** pages reaches zero it drops the database lock.
*/
SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){
- Pager *pPager;
+ TESTONLY( Pager *pPager = pPg->pPager; )
assert( pPg!=0 );
- pPager = pPg->pPager;
if( pPg->flags & PGHDR_MMAP ){
+ assert( pPg->pgno!=1 ); /* Page1 is never memory mapped */
pagerReleaseMapPage(pPg);
}else{
sqlite3PcacheRelease(pPg);
}
- pagerUnlockIfUnused(pPager);
+ /* Do not use this routine to release the last reference to page1 */
+ assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
}
SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
if( pPg ) sqlite3PagerUnrefNotNull(pPg);
}
+SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage *pPg){
+ Pager *pPager;
+ assert( pPg!=0 );
+ assert( pPg->pgno==1 );
+ assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
+ pPager = pPg->pPager;
+ sqlite3PcacheRelease(pPg);
+ pagerUnlockIfUnused(pPager);
+}
/*
** This function is called at the start of every write transaction.
@@ -53886,6 +53957,21 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
sqlite3PcacheCleanAll(pPager->pPCache);
}
}else{
+ /* The bBatch boolean is true if the batch-atomic-write commit method
+ ** should be used. No rollback journal is created if batch-atomic-write
+ ** is enabled.
+ */
+ sqlite3_file *fd = pPager->fd;
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ const int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
+ && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
+ && !pPager->noSync
+ && sqlite3JournalIsInMemory(pPager->jfd);
+#else
+# define bBatch 0
+#endif
+
+#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
@@ -53909,33 +53995,40 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
** in 'direct' mode. In this case the journal file will never be
** created for this transaction.
*/
- #ifdef SQLITE_ENABLE_ATOMIC_WRITE
- PgHdr *pPg;
- assert( isOpen(pPager->jfd)
- || pPager->journalMode==PAGER_JOURNALMODE_OFF
- || pPager->journalMode==PAGER_JOURNALMODE_WAL
- );
- if( !zMaster && isOpen(pPager->jfd)
- && pPager->journalOff==jrnlBufferSize(pPager)
- && pPager->dbSize>=pPager->dbOrigSize
- && (0==(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
- ** property of the host file-system, this is safe.
- */
- rc = pager_incr_changecounter(pPager, 1);
- }else{
- rc = sqlite3JournalCreate(pPager->jfd);
- if( rc==SQLITE_OK ){
- rc = pager_incr_changecounter(pPager, 0);
+ if( bBatch==0 ){
+ PgHdr *pPg;
+ assert( isOpen(pPager->jfd)
+ || pPager->journalMode==PAGER_JOURNALMODE_OFF
+ || pPager->journalMode==PAGER_JOURNALMODE_WAL
+ );
+ if( !zMaster && 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
+ ** property of the host file-system, this is safe.
+ */
+ rc = pager_incr_changecounter(pPager, 1);
+ }else{
+ rc = sqlite3JournalCreate(pPager->jfd);
+ if( rc==SQLITE_OK ){
+ rc = pager_incr_changecounter(pPager, 0);
+ }
}
}
- #else
+#else
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ if( zMaster ){
+ rc = sqlite3JournalCreate(pPager->jfd);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ }
+#endif
rc = pager_incr_changecounter(pPager, 0);
- #endif
+#endif
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* Write the master journal name into the journal file. If a master
@@ -53959,7 +54052,23 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
rc = syncJournal(pPager, 0);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ if( bBatch ){
+ /* The pager is now in DBMOD state. But regardless of what happens
+ ** next, attempting to play the journal back into the database would
+ ** be unsafe. Close it now to make sure that does not happen. */
+ sqlite3OsClose(pPager->jfd);
+ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ }
rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
+ if( bBatch ){
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
+ }else{
+ sqlite3OsFileControl(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
+ }
+ }
+
if( rc!=SQLITE_OK ){
assert( rc!=SQLITE_IOERR_BLOCKED );
goto commit_phase_one_exit;
@@ -54860,7 +54969,7 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint(
rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode,
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
pPager->pBusyHandlerArg,
- pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
+ pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
pnLog, pnCkpt
);
}
@@ -55017,7 +55126,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
if( rc==SQLITE_OK && pPager->pWal ){
rc = pagerExclusiveLock(pPager);
if( rc==SQLITE_OK ){
- rc = sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags,
+ rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags,
pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0;
pagerFixMaplimit(pPager);
@@ -56889,9 +56998,7 @@ static int walCheckpoint(
pInfo->nBackfillAttempted = mxSafeFrame;
/* Sync the WAL to disk */
- if( sync_flags ){
- rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
- }
+ rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
/* If the database may grow as a result of this checkpoint, hint
** about the eventual size of the db file to the VFS layer.
@@ -56932,8 +57039,8 @@ static int walCheckpoint(
i64 szDb = pWal->hdr.nPage*(i64)szPage;
testcase( IS_BIG_INT(szDb) );
rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
- if( rc==SQLITE_OK && sync_flags ){
- rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags));
}
}
if( rc==SQLITE_OK ){
@@ -58039,8 +58146,8 @@ static int walWriteToLog(
iOffset += iFirstAmt;
iAmt -= iFirstAmt;
pContent = (void*)(iFirstAmt + (char*)pContent);
- assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
- rc = sqlite3OsSync(p->pFd, p->syncFlags & SQLITE_SYNC_MASK);
+ assert( WAL_SYNC_FLAGS(p->syncFlags)!=0 );
+ rc = sqlite3OsSync(p->pFd, WAL_SYNC_FLAGS(p->syncFlags));
if( iAmt==0 || rc ) return rc;
}
rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
@@ -58210,10 +58317,10 @@ SQLITE_PRIVATE int sqlite3WalFrames(
** an out-of-order write following a WAL restart could result in
** database corruption. See the ticket:
**
- ** http://localhost:591/sqlite/info/ff5be73dee
+ ** https://sqlite.org/src/info/ff5be73dee
*/
- if( pWal->syncHeader && sync_flags ){
- rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
+ if( pWal->syncHeader ){
+ rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
if( rc ) return rc;
}
}
@@ -58288,7 +58395,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
** sector boundary is synced; the part of the last frame that extends
** past the sector boundary is written after the sync.
*/
- if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
+ if( isCommit && WAL_SYNC_FLAGS(sync_flags)!=0 ){
int bSync = 1;
if( pWal->padToSectorBoundary ){
int sectorSize = sqlite3SectorSize(pWal->pWalFd);
@@ -58304,7 +58411,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
}
if( bSync ){
assert( rc==SQLITE_OK );
- rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
+ rc = sqlite3OsSync(w.pFd, WAL_SYNC_FLAGS(sync_flags));
}
}
@@ -59152,6 +59259,11 @@ struct CellInfo {
** eState==FAULT: Cursor fault with skipNext as error code.
*/
struct BtCursor {
+ u8 eState; /* One of the CURSOR_XXX constants (see below) */
+ u8 curFlags; /* zero or more BTCF_* flags defined below */
+ u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */
+ u8 hints; /* As configured by CursorSetHints() */
+ int nOvflAlloc; /* Allocated size of aOverflow[] array */
Btree *pBtree; /* The Btree to which this cursor belongs */
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext; /* Forms a linked list of all cursors */
@@ -59160,13 +59272,8 @@ struct BtCursor {
i64 nKey; /* Size of pKey, or last integer key */
void *pKey; /* Saved key that was cursor last known position */
Pgno pgnoRoot; /* The root page of this tree */
- int nOvflAlloc; /* Allocated size of aOverflow[] array */
int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
** Error code if eState==CURSOR_FAULT */
- u8 curFlags; /* zero or more BTCF_* flags defined below */
- u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */
- u8 eState; /* One of the CURSOR_XXX constants (see below) */
- u8 hints; /* As configured by CursorSetHints() */
/* All fields above are zeroed when the cursor is allocated. See
** sqlite3BtreeCursorZero(). Fields that follow must be manually
** initialized. */
@@ -59175,7 +59282,8 @@ struct BtCursor {
u16 ix; /* Current index for apPage[iPage] */
u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */
struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */
- MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
+ MemPage *pPage; /* Current page */
+ MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */
};
/*
@@ -60091,7 +60199,9 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){
#endif /* SQLITE_OMIT_SHARED_CACHE */
-static void releasePage(MemPage *pPage); /* Forward reference */
+static void releasePage(MemPage *pPage); /* Forward reference */
+static void releasePageOne(MemPage *pPage); /* Forward reference */
+static void releasePageNotNull(MemPage *pPage); /* Forward reference */
/*
***** This routine is used inside of assert() only ****
@@ -60250,11 +60360,13 @@ static void btreeClearHasContent(BtShared *pBt){
*/
static void btreeReleaseAllCursorPages(BtCursor *pCur){
int i;
- for(i=0; i<=pCur->iPage; i++){
- releasePage(pCur->apPage[i]);
- pCur->apPage[i] = 0;
+ if( pCur->iPage>=0 ){
+ for(i=0; i<pCur->iPage; i++){
+ releasePageNotNull(pCur->apPage[i]);
+ }
+ releasePageNotNull(pCur->pPage);
+ pCur->iPage = -1;
}
- pCur->iPage = -1;
}
/*
@@ -60383,7 +60495,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(
return rc;
}
}else{
- testcase( p->iPage>0 );
+ testcase( p->iPage>=0 );
btreeReleaseAllCursorPages(p);
}
}
@@ -60423,7 +60535,7 @@ static int btreeMoveto(
if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
if( pIdxKey->nField==0 ){
- rc = SQLITE_CORRUPT_PGNO(pCur->apPage[pCur->iPage]->pgno);
+ rc = SQLITE_CORRUPT_BKPT;
goto moveto_done;
}
}else{
@@ -60488,6 +60600,17 @@ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){
}
/*
+** Return a pointer to a fake BtCursor object that will always answer
+** false to the sqlite3BtreeCursorHasMoved() routine above. The fake
+** cursor returned must not be used with any other Btree interface.
+*/
+SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void){
+ static u8 fakeCursor = CURSOR_VALID;
+ assert( offsetof(BtCursor, eState)==0 );
+ return (BtCursor*)&fakeCursor;
+}
+
+/*
** 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).
@@ -61036,8 +61159,11 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
int sz2 = 0;
int sz = get2byte(&data[iFree+2]);
int top = get2byte(&data[hdr+5]);
+ if( top>=iFree ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
if( iFree2 ){
- if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */
sz2 = get2byte(&data[iFree2+2]);
assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize );
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
@@ -61126,16 +61252,10 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
int pc = get2byte(&aData[iAddr]);
int x;
int usableSize = pPg->pBt->usableSize;
+ int size; /* Size of the free slot */
assert( pc>0 );
- do{
- int size; /* Size of the free slot */
- /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
- ** increasing offset. */
- if( pc>usableSize-4 || pc<iAddr+4 ){
- *pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
- return 0;
- }
+ while( pc<=usableSize-4 ){
/* 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. */
@@ -61143,7 +61263,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
if( (x = size - nByte)>=0 ){
testcase( x==4 );
testcase( x==3 );
- if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){
+ if( size+pc > usableSize ){
*pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
return 0;
}else if( x<4 ){
@@ -61164,7 +61284,11 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
}
iAddr = pc;
pc = get2byte(&aData[pc]);
- }while( pc );
+ if( pc<iAddr+size ) break;
+ }
+ if( pc ){
+ *pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
+ }
return 0;
}
@@ -61278,7 +61402,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
u8 hdr; /* Page header size. 0 or 100 */
u8 nFrag = 0; /* Reduction in fragmentation */
u16 iOrigSize = iSize; /* Original value of iSize */
- u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */
+ u16 x; /* Offset to cell content area */
u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */
unsigned char *data = pPage->aData; /* Page content */
@@ -61288,13 +61412,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( iSize>=4 ); /* Minimum cell size is 4 */
- assert( iStart<=iLast );
-
- /* Overwrite deleted information with zeros when the secure_delete
- ** option is enabled */
- if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
- memset(&data[iStart], 0, iSize);
- }
+ assert( iStart<=pPage->pBt->usableSize-4 );
/* The list of freeblocks must be in ascending order. Find the
** spot on the list where iStart should be inserted.
@@ -61311,7 +61429,9 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}
iPtr = iFreeBlk;
}
- if( iFreeBlk>iLast ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ if( iFreeBlk>pPage->pBt->usableSize-4 ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
assert( iFreeBlk>iPtr || iFreeBlk==0 );
/* At this point:
@@ -61347,19 +61467,25 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
data[hdr+7] -= nFrag;
}
- if( iStart==get2byte(&data[hdr+5]) ){
+ x = get2byte(&data[hdr+5]);
+ 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( iPtr!=hdr+1 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
put2byte(&data[hdr+1], iFreeBlk);
put2byte(&data[hdr+5], iEnd);
}else{
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
- put2byte(&data[iStart], iFreeBlk);
- put2byte(&data[iStart+2], iSize);
}
+ if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
+ /* Overwrite deleted information with zeros when the secure_delete
+ ** option is enabled */
+ memset(&data[iStart], 0, iSize);
+ }
+ put2byte(&data[iStart], iFreeBlk);
+ put2byte(&data[iStart+2], iSize);
pPage->nFree += iOrigSize;
return SQLITE_OK;
}
@@ -61674,7 +61800,7 @@ static Pgno btreePagecount(BtShared *pBt){
}
SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
assert( sqlite3BtreeHoldsMutex(p) );
- assert( ((p->pBt->nPage)&0x8000000)==0 );
+ assert( ((p->pBt->nPage)&0x80000000)==0 );
return btreePagecount(p->pBt);
}
@@ -61701,7 +61827,7 @@ static int getAndInitPage(
int rc;
DbPage *pDbPage;
assert( sqlite3_mutex_held(pBt->mutex) );
- assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] );
+ assert( pCur==0 || ppPage==&pCur->pPage );
assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
assert( pCur==0 || pCur->iPage>0 );
@@ -61735,7 +61861,10 @@ static int getAndInitPage(
return SQLITE_OK;
getAndInitPage_error:
- if( pCur ) pCur->iPage--;
+ if( pCur ){
+ pCur->iPage--;
+ pCur->pPage = pCur->apPage[pCur->iPage];
+ }
testcase( pgno==0 );
assert( pgno!=0 || rc==SQLITE_CORRUPT );
return rc;
@@ -61744,6 +61873,8 @@ getAndInitPage_error:
/*
** Release a MemPage. This should be called once for each prior
** call to btreeGetPage.
+**
+** Page1 is a special case and must be released using releasePageOne().
*/
static void releasePageNotNull(MemPage *pPage){
assert( pPage->aData );
@@ -61757,6 +61888,16 @@ static void releasePageNotNull(MemPage *pPage){
static void releasePage(MemPage *pPage){
if( pPage ) releasePageNotNull(pPage);
}
+static void releasePageOne(MemPage *pPage){
+ assert( pPage!=0 );
+ assert( pPage->aData );
+ assert( pPage->pBt );
+ assert( pPage->pDbPage!=0 );
+ assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
+ assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ sqlite3PagerUnrefPageOne(pPage->pDbPage);
+}
/*
** Get an unused page.
@@ -62541,7 +62682,8 @@ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){
** set to the value passed to this function as the second parameter,
** set it so.
*/
-#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
+#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS \
+ && !defined(SQLITE_OMIT_WAL)
static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){
sqlite3 *db;
Db *pDb;
@@ -62675,7 +62817,7 @@ static int lockBtree(BtShared *pBt){
}else{
setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1);
if( isOpen==0 ){
- releasePage(pPage1);
+ releasePageOne(pPage1);
return SQLITE_OK;
}
}
@@ -62722,7 +62864,7 @@ static int lockBtree(BtShared *pBt){
** zero and return SQLITE_OK. The caller will call this function
** again with the correct page-size.
*/
- releasePage(pPage1);
+ releasePageOne(pPage1);
pBt->usableSize = usableSize;
pBt->pageSize = pageSize;
freeTempSpace(pBt);
@@ -62776,7 +62918,7 @@ static int lockBtree(BtShared *pBt){
return SQLITE_OK;
page1_init_failed:
- releasePage(pPage1);
+ releasePageOne(pPage1);
pBt->pPage1 = 0;
return rc;
}
@@ -62821,7 +62963,7 @@ static void unlockBtreeIfUnused(BtShared *pBt){
assert( pPage1->aData );
assert( sqlite3PagerRefcount(pBt->pPager)==1 );
pBt->pPage1 = 0;
- releasePageNotNull(pPage1);
+ releasePageOne(pPage1);
}
}
@@ -63687,7 +63829,6 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr
if( pBtree ){
sqlite3BtreeEnter(pBtree);
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
- int i;
if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
rc = saveCursorPosition(p);
@@ -63701,10 +63842,7 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr
p->eState = CURSOR_FAULT;
p->skipNext = errCode;
}
- for(i=0; i<=p->iPage; i++){
- releasePage(p->apPage[i]);
- p->apPage[i] = 0;
- }
+ btreeReleaseAllCursorPages(p);
}
sqlite3BtreeLeave(pBtree);
}
@@ -63761,7 +63899,7 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
testcase( pBt->nPage!=nPage );
pBt->nPage = nPage;
- releasePage(pPage1);
+ releasePageOne(pPage1);
}
assert( countValidCursors(pBt, 1)==0 );
pBt->inTransaction = TRANS_READ;
@@ -64003,10 +64141,8 @@ SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){
SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
Btree *pBtree = pCur->pBtree;
if( pBtree ){
- int i;
BtShared *pBt = pCur->pBt;
sqlite3BtreeEnter(pBtree);
- sqlite3BtreeClearCursor(pCur);
assert( pBt->pCursor!=0 );
if( pBt->pCursor==pCur ){
pBt->pCursor = pCur->pNext;
@@ -64020,12 +64156,10 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
pPrev = pPrev->pNext;
}while( ALWAYS(pPrev) );
}
- for(i=0; i<=pCur->iPage; i++){
- releasePage(pCur->apPage[i]);
- }
+ btreeReleaseAllCursorPages(pCur);
unlockBtreeIfUnused(pBt);
sqlite3_free(pCur->aOverflow);
- /* sqlite3_free(pCur); */
+ sqlite3_free(pCur->pKey);
sqlite3BtreeLeave(pBtree);
}
return SQLITE_OK;
@@ -64042,9 +64176,8 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
#ifndef NDEBUG
static void assertCellInfo(BtCursor *pCur){
CellInfo info;
- int iPage = pCur->iPage;
memset(&info, 0, sizeof(info));
- btreeParseCell(pCur->apPage[iPage], pCur->ix, &info);
+ btreeParseCell(pCur->pPage, pCur->ix, &info);
assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 );
}
#else
@@ -64052,9 +64185,8 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
#endif
static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
if( pCur->info.nSize==0 ){
- int iPage = pCur->iPage;
pCur->curFlags |= BTCF_ValidNKey;
- btreeParseCell(pCur->apPage[iPage],pCur->ix,&pCur->info);
+ btreeParseCell(pCur->pPage,pCur->ix,&pCur->info);
}else{
assertCellInfo(pCur);
}
@@ -64252,7 +64384,7 @@ static int accessPayload(
unsigned char *aPayload;
int rc = SQLITE_OK;
int iIdx = 0;
- MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
+ MemPage *pPage = pCur->pPage; /* Btree page of current entry */
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
#ifdef SQLITE_DIRECT_OVERFLOW_READ
unsigned char * const pBufStart = pBuf; /* Start of original out buffer */
@@ -64448,8 +64580,8 @@ static int accessPayload(
SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
- assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
- assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
+ assert( pCur->iPage>=0 && pCur->pPage );
+ assert( pCur->ix<pCur->pPage->nCell );
return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
}
@@ -64506,18 +64638,23 @@ static const void *fetchPayload(
BtCursor *pCur, /* Cursor pointing to entry to read from */
u32 *pAmt /* Write the number of available bytes here */
){
- u32 amt;
- assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
+ int amt;
+ assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage);
assert( pCur->eState==CURSOR_VALID );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorOwnsBtShared(pCur) );
- assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
+ assert( pCur->ix<pCur->pPage->nCell );
assert( pCur->info.nSize>0 );
- assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
- assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
- amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
- if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal;
- *pAmt = amt;
+ assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB );
+ assert( pCur->info.pPayload<pCur->pPage->aDataEnd ||CORRUPT_DB);
+ amt = pCur->info.nLocal;
+ if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){
+ /* There is too little space on the page for the expected amount
+ ** of local content. Database must be corrupt. */
+ assert( CORRUPT_DB );
+ amt = MAX(0, (int)(pCur->pPage->aDataEnd - pCur->info.pPayload));
+ }
+ *pAmt = (u32)amt;
return (void*)pCur->info.pPayload;
}
@@ -64562,10 +64699,11 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
}
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
- pCur->aiIdx[pCur->iPage++] = pCur->ix;
+ pCur->aiIdx[pCur->iPage] = pCur->ix;
+ pCur->apPage[pCur->iPage] = pCur->pPage;
pCur->ix = 0;
- return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage],
- pCur, pCur->curPagerFlags);
+ pCur->iPage++;
+ return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags);
}
#ifdef SQLITE_DEBUG
@@ -64599,20 +64737,23 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
** the largest cell index.
*/
static void moveToParent(BtCursor *pCur){
+ MemPage *pLeaf;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
- assert( pCur->apPage[pCur->iPage] );
+ assert( pCur->pPage );
assertParentIndex(
pCur->apPage[pCur->iPage-1],
pCur->aiIdx[pCur->iPage-1],
- pCur->apPage[pCur->iPage]->pgno
+ pCur->pPage->pgno
);
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
pCur->ix = pCur->aiIdx[pCur->iPage-1];
- releasePageNotNull(pCur->apPage[pCur->iPage--]);
+ pLeaf = pCur->pPage;
+ pCur->pPage = pCur->apPage[--pCur->iPage];
+ releasePageNotNull(pLeaf);
}
/*
@@ -64624,9 +64765,9 @@ static void moveToParent(BtCursor *pCur){
** 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
-** CURSOR_INVALID. 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.
+** 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
@@ -64644,37 +64785,40 @@ static int moveToRoot(BtCursor *pCur){
assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
- if( pCur->eState>=CURSOR_REQUIRESEEK ){
- if( pCur->eState==CURSOR_FAULT ){
- assert( pCur->skipNext!=SQLITE_OK );
- return pCur->skipNext;
- }
- sqlite3BtreeClearCursor(pCur);
- }
+ assert( pCur->eState < CURSOR_REQUIRESEEK || pCur->iPage<0 );
+ assert( pCur->pgnoRoot>0 || pCur->iPage<0 );
if( pCur->iPage>=0 ){
if( pCur->iPage ){
- do{
- assert( pCur->apPage[pCur->iPage]!=0 );
- releasePageNotNull(pCur->apPage[pCur->iPage--]);
- }while( pCur->iPage);
+ releasePageNotNull(pCur->pPage);
+ while( --pCur->iPage ){
+ releasePageNotNull(pCur->apPage[pCur->iPage]);
+ }
+ pCur->pPage = pCur->apPage[0];
goto skip_init;
}
}else if( pCur->pgnoRoot==0 ){
pCur->eState = CURSOR_INVALID;
- return SQLITE_OK;
+ return SQLITE_EMPTY;
}else{
assert( pCur->iPage==(-1) );
- rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
+ if( pCur->eState>=CURSOR_REQUIRESEEK ){
+ if( pCur->eState==CURSOR_FAULT ){
+ assert( pCur->skipNext!=SQLITE_OK );
+ return pCur->skipNext;
+ }
+ sqlite3BtreeClearCursor(pCur);
+ }
+ rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage,
0, pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
- return rc;
+ return rc;
}
pCur->iPage = 0;
- pCur->curIntKey = pCur->apPage[0]->intKey;
+ pCur->curIntKey = pCur->pPage->intKey;
}
- pRoot = pCur->apPage[0];
+ pRoot = pCur->pPage;
assert( pRoot->pgno==pCur->pgnoRoot );
/* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor
@@ -64689,7 +64833,7 @@ static int moveToRoot(BtCursor *pCur){
** (or the freelist). */
assert( pRoot->intKey==1 || pRoot->intKey==0 );
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
- return SQLITE_CORRUPT_PGNO(pCur->apPage[pCur->iPage]->pgno);
+ return SQLITE_CORRUPT_PGNO(pCur->pPage->pgno);
}
skip_init:
@@ -64697,7 +64841,7 @@ skip_init:
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
- pRoot = pCur->apPage[0];
+ pRoot = pCur->pPage;
if( pRoot->nCell>0 ){
pCur->eState = CURSOR_VALID;
}else if( !pRoot->leaf ){
@@ -64708,6 +64852,7 @@ skip_init:
rc = moveToChild(pCur, subpage);
}else{
pCur->eState = CURSOR_INVALID;
+ rc = SQLITE_EMPTY;
}
return rc;
}
@@ -64726,7 +64871,7 @@ static int moveToLeftmost(BtCursor *pCur){
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
- while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
+ while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
assert( pCur->ix<pPage->nCell );
pgno = get4byte(findCell(pPage, pCur->ix));
rc = moveToChild(pCur, pgno);
@@ -64751,7 +64896,7 @@ static int moveToRightmost(BtCursor *pCur){
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
- while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
+ while( !(pPage = pCur->pPage)->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
pCur->ix = pPage->nCell;
rc = moveToChild(pCur, pgno);
@@ -64774,14 +64919,13 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
- if( pCur->eState==CURSOR_INVALID ){
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
- *pRes = 1;
- }else{
- assert( pCur->apPage[pCur->iPage]->nCell>0 );
- *pRes = 0;
- rc = moveToLeftmost(pCur);
- }
+ assert( pCur->pPage->nCell>0 );
+ *pRes = 0;
+ rc = moveToLeftmost(pCur);
+ }else if( rc==SQLITE_EMPTY ){
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ *pRes = 1;
+ rc = SQLITE_OK;
}
return rc;
}
@@ -64805,28 +64949,26 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
for(ii=0; ii<pCur->iPage; ii++){
assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
}
- assert( pCur->ix==pCur->apPage[pCur->iPage]->nCell-1 );
- assert( pCur->apPage[pCur->iPage]->leaf );
+ assert( pCur->ix==pCur->pPage->nCell-1 );
+ assert( pCur->pPage->leaf );
#endif
return SQLITE_OK;
}
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
- if( CURSOR_INVALID==pCur->eState ){
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
- *pRes = 1;
+ assert( pCur->eState==CURSOR_VALID );
+ *pRes = 0;
+ rc = moveToRightmost(pCur);
+ if( rc==SQLITE_OK ){
+ pCur->curFlags |= BTCF_AtLast;
}else{
- assert( pCur->eState==CURSOR_VALID );
- *pRes = 0;
- rc = moveToRightmost(pCur);
- if( rc==SQLITE_OK ){
- pCur->curFlags |= BTCF_AtLast;
- }else{
- pCur->curFlags &= ~BTCF_AtLast;
- }
-
+ pCur->curFlags &= ~BTCF_AtLast;
}
+ }else if( rc==SQLITE_EMPTY ){
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ *pRes = 1;
+ rc = SQLITE_OK;
}
return rc;
}
@@ -64925,22 +65067,23 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
rc = moveToRoot(pCur);
if( rc ){
+ if( rc==SQLITE_EMPTY ){
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ *pRes = -1;
+ return SQLITE_OK;
+ }
return rc;
}
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] );
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit );
- assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 );
- if( pCur->eState==CURSOR_INVALID ){
- *pRes = -1;
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
- return SQLITE_OK;
- }
- assert( pCur->apPage[0]->intKey==pCur->curIntKey );
+ assert( pCur->pPage );
+ assert( pCur->pPage->isInit );
+ assert( pCur->eState==CURSOR_VALID );
+ assert( pCur->pPage->nCell > 0 );
+ assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey );
assert( pCur->curIntKey || pIdxKey );
for(;;){
int lwr, upr, idx, c;
Pgno chldPg;
- MemPage *pPage = pCur->apPage[pCur->iPage];
+ 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
@@ -65068,7 +65211,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
*pRes = 0;
rc = SQLITE_OK;
pCur->ix = (u16)idx;
- if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
+ if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT;
goto moveto_finish;
}
if( lwr>upr ) break;
@@ -65079,7 +65222,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
assert( pPage->isInit );
if( pPage->leaf ){
- assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
+ assert( pCur->ix<pCur->pPage->nCell );
pCur->ix = (u16)idx;
*pRes = c;
rc = SQLITE_OK;
@@ -65133,9 +65276,10 @@ SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
** opcode, and it that case the cursor will always be valid and
** will always point to a leaf node. */
if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
- if( NEVER(pCur->apPage[pCur->iPage]->leaf==0) ) return -1;
+ if( NEVER(pCur->pPage->leaf==0) ) return -1;
- for(n=1, i=0; i<=pCur->iPage; i++){
+ n = pCur->pPage->nCell;
+ for(i=0; i<pCur->iPage; i++){
n *= pCur->apPage[i]->nCell;
}
return n;
@@ -65188,7 +65332,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
}
}
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
idx = ++pCur->ix;
assert( pPage->isInit );
@@ -65211,7 +65355,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
return SQLITE_DONE;
}
moveToParent(pCur);
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
}while( pCur->ix>=pPage->nCell );
if( pPage->intKey ){
return sqlite3BtreeNext(pCur, 0);
@@ -65234,7 +65378,7 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int flags){
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur);
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
if( (++pCur->ix)>=pPage->nCell ){
pCur->ix--;
return btreeNext(pCur);
@@ -65293,7 +65437,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
}
}
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
assert( pPage->isInit );
if( !pPage->leaf ){
int idx = pCur->ix;
@@ -65312,7 +65456,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
pCur->ix--;
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
if( pPage->intKey && !pPage->leaf ){
rc = sqlite3BtreePrevious(pCur, 0);
}else{
@@ -65330,7 +65474,7 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int flags){
pCur->info.nSize = 0;
if( pCur->eState!=CURSOR_VALID
|| pCur->ix==0
- || pCur->apPage[pCur->iPage]->leaf==0
+ || pCur->pPage->leaf==0
){
return btreePrevious(pCur);
}
@@ -65826,7 +65970,7 @@ static int clearCell(
unsigned char *pCell, /* First byte of the Cell */
CellInfo *pInfo /* Size information about the cell */
){
- BtShared *pBt = pPage->pBt;
+ BtShared *pBt;
Pgno ovflPgno;
int rc;
int nOvfl;
@@ -65842,6 +65986,7 @@ static int clearCell(
return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
ovflPgno = get4byte(pCell + pInfo->nSize - 4);
+ pBt = pPage->pBt;
assert( pBt->usableSize > 4 );
ovflPageSize = pBt->usableSize - 4;
nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize;
@@ -65909,21 +66054,20 @@ static int fillInCell(
){
int nPayload;
const u8 *pSrc;
- int nSrc, n, rc;
+ int nSrc, n, rc, mn;
int spaceLeft;
- MemPage *pOvfl = 0;
- MemPage *pToRelease = 0;
+ MemPage *pToRelease;
unsigned char *pPrior;
unsigned char *pPayload;
- BtShared *pBt = pPage->pBt;
- Pgno pgnoOvfl = 0;
+ BtShared *pBt;
+ Pgno pgnoOvfl;
int nHeader;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
/* pPage is not necessarily writeable since pCell might be auxiliary
** buffer space that is separate from the pPage buffer area */
- assert( pCell<pPage->aData || pCell>=&pPage->aData[pBt->pageSize]
+ assert( pCell<pPage->aData || pCell>=&pPage->aData[pPage->pBt->pageSize]
|| sqlite3PagerIswriteable(pPage->pDbPage) );
/* Fill in the header. */
@@ -65943,25 +66087,36 @@ static int fillInCell(
}
/* Fill in the payload */
+ pPayload = &pCell[nHeader];
if( nPayload<=pPage->maxLocal ){
+ /* This is the common case where everything fits on the btree page
+ ** and no overflow pages are required. */
n = nHeader + nPayload;
testcase( n==3 );
testcase( n==4 );
if( n<4 ) n = 4;
*pnSize = n;
- spaceLeft = nPayload;
- pPrior = pCell;
- }else{
- int mn = pPage->minLocal;
- n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4);
- testcase( n==pPage->maxLocal );
- testcase( n==pPage->maxLocal+1 );
- if( n > pPage->maxLocal ) n = mn;
- spaceLeft = n;
- *pnSize = n + nHeader + 4;
- pPrior = &pCell[nHeader+n];
+ assert( nSrc<=nPayload );
+ testcase( nSrc<nPayload );
+ memcpy(pPayload, pSrc, nSrc);
+ memset(pPayload+nSrc, 0, nPayload-nSrc);
+ return SQLITE_OK;
}
- pPayload = &pCell[nHeader];
+
+ /* If we reach this point, it means that some of the content will need
+ ** to spill onto overflow pages.
+ */
+ mn = pPage->minLocal;
+ n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4);
+ testcase( n==pPage->maxLocal );
+ testcase( n==pPage->maxLocal+1 );
+ if( n > pPage->maxLocal ) n = mn;
+ spaceLeft = n;
+ *pnSize = n + nHeader + 4;
+ pPrior = &pCell[nHeader+n];
+ pToRelease = 0;
+ pgnoOvfl = 0;
+ pBt = pPage->pBt;
/* At this point variables should be set as follows:
**
@@ -65987,8 +66142,35 @@ static int fillInCell(
#endif
/* Write the payload into the local Cell and any extra into overflow pages */
- while( nPayload>0 ){
+ while( 1 ){
+ n = nPayload;
+ if( n>spaceLeft ) n = spaceLeft;
+
+ /* If pToRelease is not zero than pPayload points into the data area
+ ** of pToRelease. Make sure pToRelease is still writeable. */
+ assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) );
+
+ /* If pPayload is part of the data area of pPage, then make sure pPage
+ ** is still writeable */
+ assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize]
+ || sqlite3PagerIswriteable(pPage->pDbPage) );
+
+ if( nSrc>=n ){
+ memcpy(pPayload, pSrc, n);
+ }else if( nSrc>0 ){
+ n = nSrc;
+ memcpy(pPayload, pSrc, n);
+ }else{
+ memset(pPayload, 0, n);
+ }
+ nPayload -= n;
+ if( nPayload<=0 ) break;
+ pPayload += n;
+ pSrc += n;
+ nSrc -= n;
+ spaceLeft -= n;
if( spaceLeft==0 ){
+ MemPage *pOvfl = 0;
#ifndef SQLITE_OMIT_AUTOVACUUM
Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */
if( pBt->autoVacuum ){
@@ -66041,30 +66223,6 @@ static int fillInCell(
pPayload = &pOvfl->aData[4];
spaceLeft = pBt->usableSize - 4;
}
- n = nPayload;
- if( n>spaceLeft ) n = spaceLeft;
-
- /* If pToRelease is not zero than pPayload points into the data area
- ** of pToRelease. Make sure pToRelease is still writeable. */
- assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) );
-
- /* If pPayload is part of the data area of pPage, then make sure pPage
- ** is still writeable */
- assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize]
- || sqlite3PagerIswriteable(pPage->pDbPage) );
-
- if( nSrc>0 ){
- if( n>nSrc ) n = nSrc;
- assert( pSrc );
- memcpy(pPayload, pSrc, n);
- }else{
- memset(pPayload, 0, n);
- }
- nPayload -= n;
- pPayload += n;
- pSrc += n;
- nSrc -= n;
- spaceLeft -= n;
}
releasePage(pToRelease);
return SQLITE_OK;
@@ -66096,7 +66254,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
hdr = pPage->hdrOffset;
testcase( pc==get2byte(&data[hdr+5]) );
testcase( pc+sz==pPage->pBt->usableSize );
- if( pc < (u32)get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){
+ if( pc+sz > pPage->pBt->usableSize ){
*pRC = SQLITE_CORRUPT_BKPT;
return;
}
@@ -66963,10 +67121,8 @@ static int balance_nonroot(
+ nMaxCells*sizeof(u16) /* b.szCell */
+ pBt->pageSize; /* aSpace1 */
- /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer
- ** that is more than 6 times the database page size. */
assert( szScratch<=6*(int)pBt->pageSize );
- b.apCell = sqlite3ScratchMalloc( szScratch );
+ b.apCell = sqlite3StackAllocRaw(0, szScratch );
if( b.apCell==0 ){
rc = SQLITE_NOMEM_BKPT;
goto balance_cleanup;
@@ -67544,7 +67700,7 @@ static int balance_nonroot(
** Cleanup before returning.
*/
balance_cleanup:
- sqlite3ScratchFree(b.apCell);
+ sqlite3StackFree(0, b.apCell);
for(i=0; i<nOld; i++){
releasePage(apOld[i]);
}
@@ -67643,7 +67799,7 @@ static int balance(BtCursor *pCur){
do {
int iPage = pCur->iPage;
- MemPage *pPage = pCur->apPage[iPage];
+ MemPage *pPage = pCur->pPage;
if( iPage==0 ){
if( pPage->nOverflow ){
@@ -67659,7 +67815,9 @@ static int balance(BtCursor *pCur){
pCur->iPage = 1;
pCur->ix = 0;
pCur->aiIdx[0] = 0;
- assert( pCur->apPage[1]->nOverflow );
+ pCur->apPage[0] = pPage;
+ pCur->pPage = pCur->apPage[1];
+ assert( pCur->pPage->nOverflow );
}
}else{
break;
@@ -67739,6 +67897,7 @@ static int balance(BtCursor *pCur){
releasePage(pPage);
pCur->iPage--;
assert( pCur->iPage>=0 );
+ pCur->pPage = pCur->apPage[pCur->iPage];
}
}while( rc==SQLITE_OK );
@@ -67870,7 +68029,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
}
assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 );
assert( pPage->leaf || !pPage->intKey );
@@ -67957,10 +68116,10 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
** 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->apPage[pCur->iPage]->nOverflow = 0;
+ pCur->pPage->nOverflow = 0;
pCur->eState = CURSOR_INVALID;
if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){
- rc = moveToRoot(pCur);
+ btreeReleaseAllCursorPages(pCur);
if( pCur->pKeyInfo ){
assert( pCur->pKey==0 );
pCur->pKey = sqlite3Malloc( pX->nKey );
@@ -67974,7 +68133,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
pCur->nKey = pX->nKey;
}
}
- assert( pCur->apPage[pCur->iPage]->nOverflow==0 );
+ assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 );
end_insert:
return rc;
@@ -68015,13 +68174,13 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
assert( pCur->curFlags & BTCF_WriteFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
- assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
+ assert( pCur->ix<pCur->pPage->nCell );
assert( pCur->eState==CURSOR_VALID );
assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
iCellDepth = pCur->iPage;
iCellIdx = pCur->ix;
- pPage = pCur->apPage[iCellDepth];
+ pPage = pCur->pPage;
pCell = findCell(pPage, iCellIdx);
/* If the bPreserve flag is set to true, then the cursor position must
@@ -68087,11 +68246,16 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** node. The cell from the leaf node needs to be moved to the internal
** node to replace the deleted cell. */
if( !pPage->leaf ){
- MemPage *pLeaf = pCur->apPage[pCur->iPage];
+ MemPage *pLeaf = pCur->pPage;
int nCell;
- Pgno n = pCur->apPage[iCellDepth+1]->pgno;
+ Pgno n;
unsigned char *pTmp;
+ if( iCellDepth<pCur->iPage-1 ){
+ n = pCur->apPage[iCellDepth+1]->pgno;
+ }else{
+ n = pCur->pPage->pgno;
+ }
pCell = findCell(pLeaf, pLeaf->nCell-1);
if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
nCell = pLeaf->xCellSize(pLeaf, pCell);
@@ -68123,16 +68287,19 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** well. */
rc = balance(pCur);
if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){
+ releasePageNotNull(pCur->pPage);
+ pCur->iPage--;
while( pCur->iPage>iCellDepth ){
releasePage(pCur->apPage[pCur->iPage--]);
}
+ pCur->pPage = pCur->apPage[pCur->iPage];
rc = balance(pCur);
}
if( rc==SQLITE_OK ){
if( bSkipnext ){
assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) );
- assert( pPage==pCur->apPage[pCur->iPage] || CORRUPT_DB );
+ assert( pPage==pCur->pPage || CORRUPT_DB );
assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
pCur->eState = CURSOR_SKIPNEXT;
if( iCellIdx>=pPage->nCell ){
@@ -68144,8 +68311,10 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
}else{
rc = moveToRoot(pCur);
if( bPreserve ){
+ btreeReleaseAllCursorPages(pCur);
pCur->eState = CURSOR_REQUIRESEEK;
}
+ if( rc==SQLITE_EMPTY ) rc = SQLITE_OK;
}
}
return rc;
@@ -68610,11 +68779,11 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
i64 nEntry = 0; /* Value to return in *pnEntry */
int rc; /* Return code */
- if( pCur->pgnoRoot==0 ){
+ rc = moveToRoot(pCur);
+ if( rc==SQLITE_EMPTY ){
*pnEntry = 0;
return SQLITE_OK;
}
- rc = moveToRoot(pCur);
/* Unless an error occurs, the following loop runs one iteration for each
** page in the B-Tree structure (not including overflow pages).
@@ -68627,7 +68796,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
** this page contains countable entries. Increment the entry counter
** accordingly.
*/
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
if( pPage->leaf || !pPage->intKey ){
nEntry += pPage->nCell;
}
@@ -68650,10 +68819,10 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
return moveToRoot(pCur);
}
moveToParent(pCur);
- }while ( pCur->ix>=pCur->apPage[pCur->iPage]->nCell );
+ }while ( pCur->ix>=pCur->pPage->nCell );
pCur->ix++;
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
}
/* Descend to the child node of the cell that the cursor currently
@@ -69494,7 +69663,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
&& pCsr->pBt->inTransaction==TRANS_WRITE );
assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) );
- assert( pCsr->apPage[pCsr->iPage]->intKey );
+ assert( pCsr->pPage->intKey );
return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
}
@@ -70520,7 +70689,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre
assert( pMem->szMalloc==0
|| pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
if( n<32 ) n = 32;
- if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
+ if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
bPreserve = 0;
}else{
@@ -70536,7 +70705,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
}
- if( bPreserve && pMem->z && ALWAYS(pMem->z!=pMem->zMalloc) ){
+ if( bPreserve && pMem->z ){
+ assert( pMem->z!=pMem->zMalloc );
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( (pMem->flags&MEM_Dyn)!=0 ){
@@ -70575,6 +70745,20 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
}
/*
+** It is already known that pMem contains an unterminated string.
+** Add the zero terminator.
+*/
+static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
+ if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
+ return SQLITE_NOMEM_BKPT;
+ }
+ pMem->z[pMem->n] = 0;
+ pMem->z[pMem->n+1] = 0;
+ pMem->flags |= MEM_Term;
+ return SQLITE_OK;
+}
+
+/*
** Change pMem so that its MEM_Str or MEM_Blob value is stored in
** MEM.zMalloc, where it can be safely written.
**
@@ -70586,12 +70770,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
- if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
- return SQLITE_NOMEM_BKPT;
- }
- pMem->z[pMem->n] = 0;
- pMem->z[pMem->n+1] = 0;
- pMem->flags |= MEM_Term;
+ int rc = vdbeMemAddTerminator(pMem);
+ if( rc ) return rc;
}
}
pMem->flags &= ~MEM_Ephem;
@@ -70631,20 +70811,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
#endif
/*
-** It is already known that pMem contains an unterminated string.
-** Add the zero terminator.
-*/
-static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
- if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
- return SQLITE_NOMEM_BKPT;
- }
- pMem->z[pMem->n] = 0;
- pMem->z[pMem->n+1] = 0;
- pMem->flags |= MEM_Term;
- return SQLITE_OK;
-}
-
-/*
** Make sure the given Mem is \u0000 terminated.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){
@@ -70962,14 +71128,21 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){
*/
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
+ int rc;
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
+ rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc);
+ if( rc==0 ){
MemSetTypeFlag(pMem, MEM_Int);
}else{
- pMem->u.r = sqlite3VdbeRealValue(pMem);
- MemSetTypeFlag(pMem, MEM_Real);
- sqlite3VdbeIntegerAffinity(pMem);
+ i64 i = pMem->u.i;
+ sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
+ if( rc==1 && pMem->u.r==(double)i ){
+ pMem->u.i = i;
+ MemSetTypeFlag(pMem, MEM_Int);
+ }else{
+ MemSetTypeFlag(pMem, MEM_Real);
+ }
}
}
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
@@ -71289,7 +71462,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
if( nByte<0 ){
assert( enc!=0 );
if( enc==SQLITE_UTF8 ){
- nByte = sqlite3Strlen30(z);
+ nByte = 0x7fffffff & (int)strlen(z);
if( nByte>iLimit ) nByte = iLimit+1;
}else{
for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
@@ -71367,12 +71540,11 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
){
int rc;
pMem->flags = MEM_Null;
- if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
+ if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){
rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z);
if( rc==SQLITE_OK ){
- pMem->z[amt] = 0;
- pMem->z[amt+1] = 0;
- pMem->flags = MEM_Blob|MEM_Term;
+ pMem->z[amt] = 0; /* Overrun area used when reading malformed records */
+ pMem->flags = MEM_Blob;
pMem->n = (int)amt;
}else{
sqlite3VdbeMemRelease(pMem);
@@ -71521,7 +71693,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
if( pRec ){
pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx);
if( pRec->pKeyInfo ){
- assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol );
+ assert( pRec->pKeyInfo->nAllField==nCol );
assert( pRec->pKeyInfo->enc==ENC(db) );
pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord)));
for(i=0; i<nCol; i++){
@@ -72057,7 +72229,7 @@ SQLITE_PRIVATE int sqlite3Stat4Column(
SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
if( pRec ){
int i;
- int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField;
+ int nCol = pRec->pKeyInfo->nAllField;
Mem *aMem = pRec->aMem;
sqlite3 *db = aMem[0].db;
for(i=0; i<nCol; i++){
@@ -72153,10 +72325,12 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
db->pVdbe = p;
p->magic = VDBE_MAGIC_INIT;
p->pParse = pParse;
+ pParse->pVdbe = p;
assert( pParse->aLabel==0 );
assert( pParse->nLabel==0 );
assert( pParse->nOpAlloc==0 );
assert( pParse->szOpAlloc==0 );
+ sqlite3VdbeAddOp2(p, OP_Init, 0, 1);
return p;
}
@@ -72610,7 +72784,8 @@ static Op *opIterNext(VdbeOpIter *p){
** * OP_VUpdate
** * OP_VRename
** * OP_FkCounter with P2==0 (immediate foreign key constraint)
-** * OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...)
+** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine
+** (for CREATE TABLE AS SELECT ...)
**
** Then check that the value of Parse.mayAbort is true if an
** ABORT may be thrown, or false otherwise. Return true if it does
@@ -72638,7 +72813,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
hasAbort = 1;
break;
}
- if( opcode==OP_CreateTable ) hasCreateTable = 1;
+ if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1;
if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1;
#ifndef SQLITE_OMIT_FOREIGN_KEY
if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
@@ -72717,6 +72892,27 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
p->bIsReader = 1;
break;
}
+ case OP_Next:
+ case OP_NextIfOpen:
+ 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:
+ case OP_PrevIfOpen: {
+ 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 */
+ assert( pOp->p2>=0 );
+ break;
+ }
#ifndef SQLITE_OMIT_VIRTUALTABLE
case OP_VUpdate: {
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
@@ -72728,27 +72924,25 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
assert( pOp[-1].opcode==OP_Integer );
n = pOp[-1].p1;
if( n>nMaxArgs ) nMaxArgs = n;
- break;
+ /* Fall through into the default case */
}
#endif
- case OP_Next:
- case OP_NextIfOpen:
- case OP_SorterNext: {
- pOp->p4.xAdvance = sqlite3BtreeNext;
- pOp->p4type = P4_ADVANCE;
- break;
- }
- case OP_Prev:
- case OP_PrevIfOpen: {
- pOp->p4.xAdvance = sqlite3BtreePrevious;
- pOp->p4type = P4_ADVANCE;
+ default: {
+ if( pOp->p2<0 ){
+ /* The mkopcodeh.tcl script has so arranged things that the only
+ ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
+ ** have non-negative values for P2. */
+ assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
+ assert( ADDR(pOp->p2)<pParse->nLabel );
+ pOp->p2 = aLabel[ADDR(pOp->p2)];
+ }
break;
}
}
- if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){
- assert( ADDR(pOp->p2)<pParse->nLabel );
- pOp->p2 = aLabel[ADDR(pOp->p2)];
- }
+ /* The mkopcodeh.tcl script has so arranged things that the only
+ ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
+ ** have non-negative values for P2. */
+ assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
}
if( pOp==p->aOp ) break;
pOp--;
@@ -73421,8 +73615,8 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
int j;
KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
assert( pKeyInfo->aSortOrder!=0 );
- sqlite3XPrintf(&x, "k(%d", pKeyInfo->nField);
- for(j=0; j<pKeyInfo->nField; j++){
+ sqlite3XPrintf(&x, "k(%d", pKeyInfo->nKeyField);
+ for(j=0; j<pKeyInfo->nKeyField; j++){
CollSeq *pColl = pKeyInfo->aColl[j];
const char *zColl = pColl ? pColl->zName : "";
if( strcmp(zColl, "BINARY")==0 ) zColl = "B";
@@ -74259,27 +74453,6 @@ static void closeAllCursors(Vdbe *p){
}
/*
-** Clean up the VM after a single run.
-*/
-static void Cleanup(Vdbe *p){
- sqlite3 *db = p->db;
-
-#ifdef SQLITE_DEBUG
- /* Execute assert() statements to ensure that the Vdbe.apCsr[] and
- ** Vdbe.aMem[] arrays have already been cleaned up. */
- int i;
- 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;
-}
-
-/*
** Set the number of result columns that will be returned by this SQL
** statement. This is now set at compile time, rather than during
** execution of the vdbe program so that sqlite3_column_count() can
@@ -74987,6 +75160,10 @@ static void vdbeInvokeSqllog(Vdbe *v){
** VDBE_MAGIC_INIT.
*/
SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+ int i;
+#endif
+
sqlite3 *db;
db = p->db;
@@ -75004,8 +75181,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
if( p->pc>=0 ){
vdbeInvokeSqllog(p);
sqlite3VdbeTransferError(p);
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
if( p->runOnlyOnce ) p->expired = 1;
}else if( p->rc && p->expired ){
/* The expired flag was set on the VDBE before the first call
@@ -75013,13 +75188,21 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
** called), set the database error in this case as well.
*/
sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
}
- /* Reclaim all memory used by the VDBE
+ /* Reset register contents and reclaim error message memory.
*/
- Cleanup(p);
+#ifdef SQLITE_DEBUG
+ /* 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;
/* Save profiling information from this VDBE run.
*/
@@ -75027,7 +75210,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
{
FILE *out = fopen("vdbe_profile.out", "a");
if( out ){
- int i;
fprintf(out, "---- ");
for(i=0; i<p->nOp; i++){
fprintf(out, "%02x", p->aOp[i].opcode);
@@ -75240,19 +75422,18 @@ SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){
*/
SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
VdbeCursor *p = *pp;
- if( p->eCurType==CURTYPE_BTREE ){
- if( p->deferredMoveto ){
- int iMap;
- if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){
- *pp = p->pAltCursor;
- *piCol = iMap - 1;
- return SQLITE_OK;
- }
- return handleDeferredMoveto(p);
- }
- if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
- return handleMovedCursor(p);
+ 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 handleDeferredMoveto(p);
+ }
+ if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
+ return handleMovedCursor(p);
}
return SQLITE_OK;
}
@@ -75648,13 +75829,13 @@ 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->nField+1);
+ nByte = ROUND8(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))];
assert( pKeyInfo->aSortOrder!=0 );
p->pKeyInfo = pKeyInfo;
- p->nField = pKeyInfo->nField + 1;
+ p->nField = pKeyInfo->nKeyField + 1;
return p;
}
@@ -75694,7 +75875,7 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
pMem++;
if( (++u)>=p->nField ) break;
}
- assert( u<=pKeyInfo->nField + 1 );
+ assert( u<=pKeyInfo->nKeyField + 1 );
p->nField = u;
}
@@ -75743,9 +75924,9 @@ static int vdbeRecordCompareDebug(
idx1 = getVarint32(aKey1, szHdr1);
if( szHdr1>98307 ) return SQLITE_CORRUPT;
d1 = szHdr1;
- assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
+ assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB );
assert( pKeyInfo->aSortOrder!=0 );
- assert( pKeyInfo->nField>0 );
+ assert( pKeyInfo->nKeyField>0 );
assert( idx1<=szHdr1 || CORRUPT_DB );
do{
u32 serial_type1;
@@ -75807,12 +75988,12 @@ debugCompareEnd:
/*
** Count the number of fields (a.k.a. columns) in the record given by
** pKey,nKey. The verify that this count is less than or equal to the
-** limit given by pKeyInfo->nField + pKeyInfo->nXField.
+** limit given by pKeyInfo->nAllField.
**
** If this constraint is not satisfied, it means that the high-speed
** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will
** not work correctly. If this assert() ever fires, it probably means
-** that the KeyInfo.nField or KeyInfo.nXField values were computed
+** that the KeyInfo.nKeyField or KeyInfo.nAllField values were computed
** incorrectly.
*/
static void vdbeAssertFieldCountWithinLimits(
@@ -75833,7 +76014,7 @@ static void vdbeAssertFieldCountWithinLimits(
idx += getVarint32(aKey+idx, notUsed);
nField++;
}
- assert( nField <= pKeyInfo->nField+pKeyInfo->nXField );
+ assert( nField <= pKeyInfo->nAllField );
}
#else
# define vdbeAssertFieldCountWithinLimits(A,B,C)
@@ -76138,10 +76319,10 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
}
VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
- assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
+ assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField
|| CORRUPT_DB );
assert( pPKey2->pKeyInfo->aSortOrder!=0 );
- assert( pPKey2->pKeyInfo->nField>0 );
+ assert( pPKey2->pKeyInfo->nKeyField>0 );
assert( idx1<=szHdr1 || CORRUPT_DB );
do{
u32 serial_type;
@@ -76474,7 +76655,7 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
** The easiest way to enforce this limit is to consider only records with
** 13 fields or less. If the first field is an integer, the maximum legal
** header size is (12*5 + 1 + 1) bytes. */
- if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){
+ if( p->pKeyInfo->nAllField<=13 ){
int flags = p->aMem[0].flags;
if( p->pKeyInfo->aSortOrder[0] ){
p->r1 = 1;
@@ -76803,7 +76984,7 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
preupdate.iNewReg = iReg;
preupdate.keyinfo.db = db;
preupdate.keyinfo.enc = ENC(db);
- preupdate.keyinfo.nField = pTab->nCol;
+ preupdate.keyinfo.nKeyField = pTab->nCol;
preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder;
preupdate.iKey1 = iKey1;
preupdate.iKey2 = iKey2;
@@ -76813,8 +76994,8 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
db->pPreUpdate = 0;
sqlite3DbFree(db, preupdate.aRecord);
- vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pUnpacked);
- vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pNewUnpacked);
+ vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
+ vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
if( preupdate.aNew ){
int i;
for(i=0; i<pCsr->nField; i++){
@@ -77346,7 +77527,7 @@ static int doWalCallbacks(sqlite3 *db){
sqlite3BtreeEnter(pBt);
nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
sqlite3BtreeLeave(pBt);
- if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
+ if( nEntry>0 && db->xWalCallback && rc==SQLITE_OK ){
rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry);
}
}
@@ -77456,7 +77637,7 @@ static int sqlite3Step(Vdbe *p){
if( rc!=SQLITE_ROW ) checkProfileCallback(db, p);
#endif
- if( rc==SQLITE_DONE ){
+ if( rc==SQLITE_DONE && db->autoCommit ){
assert( p->rc==SQLITE_OK );
p->rc = doWalCallbacks(db);
if( p->rc!=SQLITE_OK ){
@@ -77500,7 +77681,6 @@ end_of_step:
*/
SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
int rc = SQLITE_OK; /* Result from sqlite3Step() */
- int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */
Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */
int cnt = 0; /* Counter to prevent infinite loop of reprepares */
sqlite3 *db; /* The database connection */
@@ -77514,32 +77694,31 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
&& cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
int savedPc = v->pc;
- rc2 = rc = sqlite3Reprepare(v);
- if( rc!=SQLITE_OK) break;
+ 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
+ ** from the database handle into the statement and sets the statement
+ ** 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);
+ sqlite3DbFree(db, v->zErrMsg);
+ if( !db->mallocFailed ){
+ v->zErrMsg = sqlite3DbStrDup(db, zErr);
+ v->rc = rc = sqlite3ApiExit(db, rc);
+ } else {
+ v->zErrMsg = 0;
+ v->rc = rc = SQLITE_NOMEM_BKPT;
+ }
+ break;
+ }
sqlite3_reset(pStmt);
if( savedPc>=0 ) v->doingRerun = 1;
assert( v->expired==0 );
}
- if( rc2!=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
- ** from the database handle into the statement and sets the statement
- ** 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);
- sqlite3DbFree(db, v->zErrMsg);
- if( !db->mallocFailed ){
- v->zErrMsg = sqlite3DbStrDup(db, zErr);
- v->rc = rc2;
- } else {
- v->zErrMsg = 0;
- v->rc = rc = SQLITE_NOMEM_BKPT;
- }
- }
- rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -78537,7 +78716,7 @@ static UnpackedRecord *vdbeUnpackRecord(
pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
if( pRet ){
- memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1));
+ memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1));
sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
}
return pRet;
@@ -78610,7 +78789,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa
*/
SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
PreUpdate *p = db->pPreUpdate;
- return (p ? p->keyinfo.nField : 0);
+ return (p ? p->keyinfo.nKeyField : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -78863,7 +79042,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
Mem *pVar; /* Value of a host parameter */
StrAccum out; /* Accumulate the output here */
#ifndef SQLITE_OMIT_UTF16
- Mem utf8; /* Used to convert UTF16 parameters into UTF8 for display */
+ Mem utf8; /* Used to convert UTF16 into UTF8 for display */
#endif
char zBase[100]; /* Initial working space */
@@ -79332,7 +79511,7 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){
return 0;
}
- if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
+ if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==0 ){
return MEM_Int;
}
return MEM_Real;
@@ -81022,13 +81201,23 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
}
compare_op:
- switch( pOp->opcode ){
- case OP_Eq: res2 = res==0; break;
- case OP_Ne: res2 = res; break;
- case OP_Lt: res2 = res<0; break;
- case OP_Le: res2 = res<=0; break;
- case OP_Gt: res2 = res>0; break;
- default: res2 = res>=0; break;
+ /* 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
+ ** operator actually is. The next block of code depends on the fact
+ ** that the 6 comparison operators are consecutive integers in this
+ ** 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];
+ }else if( res==0 ){
+ static const unsigned char aEQb[] = { 0, 1, 0, 1, 0, 1 };
+ res2 = aEQb[pOp->opcode - OP_Ne];
+ }else{
+ static const unsigned char aGTb[] = { 1, 0, 1, 0, 0, 1 };
+ res2 = aGTb[pOp->opcode - OP_Ne];
}
/* Undo any changes made by applyAffinity() to the input registers. */
@@ -81040,7 +81229,6 @@ compare_op:
if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
iCompare = res;
- res2 = res2!=0; /* For this path res2 must be exactly 0 or 1 */
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
@@ -81171,7 +81359,7 @@ case OP_Compare: {
assert( memIsValid(&aMem[p2+idx]) );
REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
- assert( i<pKeyInfo->nField );
+ assert( i<pKeyInfo->nKeyField );
pColl = pKeyInfo->aColl[i];
bRev = pKeyInfo->aSortOrder[i];
iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
@@ -81444,9 +81632,7 @@ case OP_Column: {
const u8 *zData; /* Part of the record being decoded */
const u8 *zHdr; /* Next unparsed byte of the header */
const u8 *zEndHdr; /* Pointer to first byte after the header */
- u32 offset; /* Offset into the data */
u64 offset64; /* 64-bit offset */
- u32 avail; /* Number of bytes of available data */
u32 t; /* A type code from the record header */
Mem *pReg; /* PseudoTable input register */
@@ -81473,11 +81659,13 @@ case OP_Column: {
if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/
if( pC->nullRow ){
if( pC->eCurType==CURTYPE_PSEUDO ){
- assert( pC->uc.pseudoTableReg>0 );
- pReg = &aMem[pC->uc.pseudoTableReg];
+ /* 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 = avail = pReg->n;
+ pC->payloadSize = pC->szRow = pReg->n;
pC->aRow = (u8*)pReg->z;
}else{
sqlite3VdbeMemSetNull(pDest);
@@ -81489,23 +81677,19 @@ case OP_Column: {
assert( pCrsr );
assert( sqlite3BtreeCursorIsValid(pCrsr) );
pC->payloadSize = sqlite3BtreePayloadSize(pCrsr);
- pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &avail);
- assert( avail<=65536 ); /* Maximum page size is 64KiB */
- if( pC->payloadSize <= (u32)avail ){
- pC->szRow = pC->payloadSize;
- }else if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ 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;
- }else{
- pC->szRow = avail;
}
}
pC->cacheStatus = p->cacheCtr;
- pC->iHdrOffset = getVarint32(pC->aRow, offset);
+ pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]);
pC->nHdrParsed = 0;
- aOffset[0] = offset;
- if( avail<offset ){ /*OPTIMIZATION-IF-FALSE*/
+ 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
** the complete header, then set it to zero, forcing the header to be
@@ -81522,17 +81706,26 @@ case OP_Column: {
** 3-byte type for each of the maximum of 32768 columns plus three
** extra bytes for the header length itself. 32768*3 + 3 = 98307.
*/
- if( offset > 98307 || offset > pC->payloadSize ){
- rc = SQLITE_CORRUPT_BKPT;
- goto abort_due_to_error;
+ if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){
+ goto op_column_corrupt;
}
- }else if( offset>0 ){ /*OPTIMIZATION-IF-TRUE*/
- /* The following goto is an optimization. It can be omitted and
- ** everything will still work. But OP_Column is measurably faster
- ** by skipping the subsequent conditional, which is always true.
+ }else{
+ /* This is an optimization. By skipping over the first few tests
+ ** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a
+ ** measurable performance gain.
+ **
+ ** This branch is taken even if aOffset[0]==0. Such a record is never
+ ** generated by SQLite, and could be considered corruption, but we
+ ** accept it for historical reasons. When aOffset[0]==0, the code this
+ ** branch jumps to reads past the end of the record, but never more
+ ** than a few bytes. Even if the record occurs at the end of the page
+ ** content area, the "page header" comes after the page content and so
+ ** this overread is harmless. Similar overreads can occur for a corrupt
+ ** database file.
*/
zData = pC->aRow;
assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */
+ testcase( aOffset[0]==0 );
goto op_column_read_header;
}
}
@@ -81561,6 +81754,7 @@ case OP_Column: {
offset64 = aOffset[i];
zHdr = zData + pC->iHdrOffset;
zEndHdr = zData + aOffset[0];
+ testcase( zHdr>=zEndHdr );
do{
if( (t = zHdr[0])<0x80 ){
zHdr++;
@@ -81581,9 +81775,13 @@ case OP_Column: {
if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize))
|| (offset64 > pC->payloadSize)
){
- if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
- rc = SQLITE_CORRUPT_BKPT;
- goto abort_due_to_error;
+ if( aOffset[0]==0 ){
+ i = 0;
+ zHdr = zEndHdr;
+ }else{
+ if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
+ goto op_column_corrupt;
+ }
}
pC->nHdrParsed = i;
@@ -81677,6 +81875,15 @@ op_column_out:
UPDATE_MAX_BLOBSIZE(pDest);
REGISTER_TRACE(pOp->p3, pDest);
break;
+
+op_column_corrupt:
+ if( aOp[0].p3>0 ){
+ pOp = &aOp[aOp[0].p3-1];
+ break;
+ }else{
+ rc = SQLITE_CORRUPT_BKPT;
+ goto abort_due_to_error;
+ }
}
/* Opcode: Affinity P1 P2 * P4 *
@@ -82017,7 +82224,7 @@ case OP_Savepoint: {
int isSchemaChange;
iSavepoint = db->nSavepoint - iSavepoint - 1;
if( p1==SAVEPOINT_ROLLBACK ){
- isSchemaChange = (db->flags & SQLITE_InternChanges)!=0;
+ isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0;
for(ii=0; ii<db->nDb; ii++){
rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,
SQLITE_ABORT_ROLLBACK,
@@ -82036,7 +82243,7 @@ case OP_Savepoint: {
if( isSchemaChange ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
- db->flags = (db->flags | SQLITE_InternChanges);
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
}
@@ -82316,7 +82523,7 @@ case OP_SetCookie: {
if( pOp->p2==BTREE_SCHEMA_VERSION ){
/* When the schema cookie changes, record the new cookie internally */
pDb->pSchema->schema_cookie = pOp->p3;
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}else if( pOp->p2==BTREE_FILE_FORMAT ){
/* Record changes in the file format */
pDb->pSchema->file_format = pOp->p3;
@@ -82455,7 +82662,7 @@ case OP_OpenWrite:
assert( (pIn2->flags & MEM_Int)!=0 );
sqlite3VdbeMemIntegerify(pIn2);
p2 = (int)pIn2->u.i;
- /* The p2 value always comes from a prior OP_CreateTable opcode and
+ /* The p2 value always comes from a prior OP_CreateBtree opcode and
** that opcode will always set the p2 value to 2 or more or else fail.
** If there were a failure, the prepared statement would have halted
** before reaching this instruction. */
@@ -82465,7 +82672,7 @@ case OP_OpenWrite:
pKeyInfo = pOp->p4.pKeyInfo;
assert( pKeyInfo->enc==ENC(db) );
assert( pKeyInfo->db==db );
- nField = pKeyInfo->nField+pKeyInfo->nXField;
+ nField = pKeyInfo->nAllField;
}else if( pOp->p4type==P4_INT32 ){
nField = pOp->p4.i;
}
@@ -82676,8 +82883,13 @@ case OP_OpenPseudo: {
pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
- pCx->uc.pseudoTableReg = pOp->p2;
+ pCx->seekResult = pOp->p2;
pCx->isTable = 1;
+ /* Give this pseudo-cursor a fake BtCursor pointer so that pCx
+ ** can be safely passed to sqlite3VdbeCursorMoveto(). This avoids a test
+ ** for pCx->eCurType==CURTYPE_BTREE inside of sqlite3VdbeCursorMoveto()
+ ** which is a performance optimization */
+ pCx->uc.pCursor = sqlite3BtreeFakeValidCursor();
assert( pOp->p5==0 );
break;
}
@@ -83469,14 +83681,9 @@ case OP_InsertInt: {
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
- if( pData->flags & MEM_Null ){
- x.pData = 0;
- x.nData = 0;
- }else{
- assert( pData->flags & (MEM_Blob|MEM_Str) );
- x.pData = pData->z;
- x.nData = pData->n;
- }
+ assert( pData->flags & (MEM_Blob|MEM_Str) );
+ x.pData = pData->z;
+ x.nData = pData->n;
seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0);
if( pData->flags & MEM_Zero ){
x.nZero = pData->u.nZero;
@@ -83843,7 +84050,17 @@ case OP_NullRow: {
break;
}
-/* Opcode: Last P1 P2 P3 * *
+/* Opcode: SeekEnd P1 * * * *
+**
+** Position cursor P1 at the end of the btree for the purpose of
+** appending a new entry onto the btree.
+**
+** It is assumed that the cursor is used only for appending and so
+** if the cursor is valid, then the cursor must already be pointing
+** at the end of the btree and so no changes are made to
+** the cursor.
+*/
+/* Opcode: Last P1 P2 * * *
**
** 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.
@@ -83854,14 +84071,8 @@ case OP_NullRow: {
** This opcode leaves the cursor configured to move in reverse order,
** from the end toward the beginning. In other words, the cursor is
** configured to use Prev, not Next.
-**
-** If P3 is -1, then the cursor is positioned at the end of the btree
-** for the purpose of appending a new entry onto the btree. In that
-** case P2 must be 0. It is assumed that the cursor is used only for
-** appending and so if the cursor is valid, then the cursor must already
-** be pointing at the end of the btree and so no changes are made to
-** the cursor.
*/
+case OP_SeekEnd:
case OP_Last: { /* jump */
VdbeCursor *pC;
BtCursor *pCrsr;
@@ -83874,22 +84085,24 @@ case OP_Last: { /* jump */
pCrsr = pC->uc.pCursor;
res = 0;
assert( pCrsr!=0 );
- pC->seekResult = pOp->p3;
#ifdef SQLITE_DEBUG
- pC->seekOp = OP_Last;
+ pC->seekOp = pOp->opcode;
#endif
- if( pOp->p3==0 || !sqlite3BtreeCursorIsValidNN(pCrsr) ){
- rc = sqlite3BtreeLast(pCrsr, &res);
- pC->nullRow = (u8)res;
- pC->deferredMoveto = 0;
- pC->cacheStatus = CACHE_STALE;
- if( rc ) goto abort_due_to_error;
- if( pOp->p2>0 ){
- VdbeBranchTaken(res!=0,2);
- if( res ) goto jump_to_p2;
- }
- }else{
+ if( pOp->opcode==OP_SeekEnd ){
assert( pOp->p2==0 );
+ pC->seekResult = -1;
+ if( sqlite3BtreeCursorIsValidNN(pCrsr) ){
+ break;
+ }
+ }
+ rc = sqlite3BtreeLast(pCrsr, &res);
+ pC->nullRow = (u8)res;
+ pC->deferredMoveto = 0;
+ pC->cacheStatus = CACHE_STALE;
+ if( rc ) goto abort_due_to_error;
+ if( pOp->p2>0 ){
+ VdbeBranchTaken(res!=0,2);
+ if( res ) goto jump_to_p2;
}
break;
}
@@ -84518,50 +84731,28 @@ case OP_ResetSorter: {
break;
}
-/* Opcode: CreateTable P1 P2 * * *
-** Synopsis: r[P2]=root iDb=P1
-**
-** Allocate a new table in the main database file if P1==0 or in the
-** auxiliary database file if P1==1 or in an attached database if
-** P1>1. Write the root page number of the new table into
-** register P2
-**
-** The difference between a table and an index is this: A table must
-** have a 4-byte integer key and can have arbitrary data. An index
-** has an arbitrary key but no data.
-**
-** See also: CreateIndex
-*/
-/* Opcode: CreateIndex P1 P2 * * *
-** Synopsis: r[P2]=root iDb=P1
-**
-** Allocate a new index in the main database file if P1==0 or in the
-** auxiliary database file if P1==1 or in an attached database if
-** P1>1. Write the root page number of the new table into
-** register P2.
+/* Opcode: CreateBtree P1 P2 P3 * *
+** Synopsis: r[P2]=root iDb=P1 flags=P3
**
-** See documentation on OP_CreateTable for additional information.
+** Allocate a new b-tree in the main database file if P1==0 or in the
+** TEMP database file if P1==1 or in an attached database if
+** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table
+** it must be 2 (BTREE_BLOBKEY) for a index or WITHOUT ROWID table.
+** The root page number of the new b-tree is stored in register P2.
*/
-case OP_CreateIndex: /* out2 */
-case OP_CreateTable: { /* out2 */
+case OP_CreateBtree: { /* out2 */
int pgno;
- int flags;
Db *pDb;
pOut = out2Prerelease(p, pOp);
pgno = 0;
+ assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p1) );
assert( p->readOnly==0 );
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
- if( pOp->opcode==OP_CreateTable ){
- /* flags = BTREE_INTKEY; */
- flags = BTREE_INTKEY;
- }else{
- flags = BTREE_BLOBKEY;
- }
- rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
+ rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, pOp->p3);
if( rc ) goto abort_due_to_error;
pOut->u.i = pgno;
break;
@@ -86072,7 +86263,7 @@ case OP_Function: {
}
-/* Opcode: Init P1 P2 * P4 *
+/* Opcode: Init P1 P2 P3 P4 *
** Synopsis: Start at P2
**
** Programs contain a single instance of this opcode as the very first
@@ -86086,6 +86277,9 @@ case OP_Function: {
**
** Increment the value of P1 so that OP_Once opcodes will jump the
** first time they are evaluated for this run.
+**
+** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT
+** error is encountered.
*/
case OP_Init: { /* jump */
char *zTrace;
@@ -86360,11 +86554,12 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
v->aMem[1].u.i = iRow;
/* If the statement has been run before (and is paused at the OP_ResultRow)
- ** then back it up to the point where it does the OP_SeekRowid. This could
+ ** then back it up to the point where it does the OP_NotExists. This could
** have been down with an extra OP_Goto, but simply setting the program
** counter is faster. */
- if( v->pc>3 ){
- v->pc = 3;
+ if( v->pc>4 ){
+ v->pc = 4;
+ assert( v->aOp[v->pc].opcode==OP_NotExists );
rc = sqlite3VdbeExec(v);
}else{
rc = sqlite3_step(p->pStmt);
@@ -86426,8 +86621,8 @@ SQLITE_API int sqlite3_blob_open(
int rc = SQLITE_OK;
char *zErr = 0;
Table *pTab;
- Parse *pParse = 0;
Incrblob *pBlob = 0;
+ Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppBlob==0 ){
@@ -86445,37 +86640,34 @@ SQLITE_API int sqlite3_blob_open(
sqlite3_mutex_enter(db->mutex);
pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
- if( !pBlob ) goto blob_open_out;
- pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
- if( !pParse ) goto blob_open_out;
-
do {
- memset(pParse, 0, sizeof(Parse));
- pParse->db = db;
+ memset(&sParse, 0, sizeof(Parse));
+ if( !pBlob ) goto blob_open_out;
+ sParse.db = db;
sqlite3DbFree(db, zErr);
zErr = 0;
sqlite3BtreeEnterAll(db);
- pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
+ pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
if( pTab && IsVirtual(pTab) ){
pTab = 0;
- sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);
+ sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable);
}
if( pTab && !HasRowid(pTab) ){
pTab = 0;
- sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable);
+ sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
}
#ifndef SQLITE_OMIT_VIEW
if( pTab && pTab->pSelect ){
pTab = 0;
- sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable);
+ sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
}
#endif
if( !pTab ){
- if( pParse->zErrMsg ){
+ if( sParse.zErrMsg ){
sqlite3DbFree(db, zErr);
- zErr = pParse->zErrMsg;
- pParse->zErrMsg = 0;
+ zErr = sParse.zErrMsg;
+ sParse.zErrMsg = 0;
}
rc = SQLITE_ERROR;
sqlite3BtreeLeaveAll(db);
@@ -86539,7 +86731,7 @@ SQLITE_API int sqlite3_blob_open(
}
}
- pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
+ pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse);
assert( pBlob->pStmt || db->mallocFailed );
if( pBlob->pStmt ){
@@ -86576,6 +86768,7 @@ SQLITE_API int sqlite3_blob_open(
pTab->pSchema->schema_cookie,
pTab->pSchema->iGeneration);
sqlite3VdbeChangeP5(v, 1);
+ assert( sqlite3VdbeCurrentAddr(v)==2 || db->mallocFailed );
aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
/* Make sure a mutex is held on the table to be accessed */
@@ -86590,7 +86783,7 @@ SQLITE_API int sqlite3_blob_open(
aOp[0].p1 = iDb;
aOp[0].p2 = pTab->tnum;
aOp[0].p3 = wrFlag;
- sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
+ sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
}
if( db->mallocFailed==0 ){
#endif
@@ -86612,10 +86805,10 @@ SQLITE_API int sqlite3_blob_open(
aOp[1].p4.i = pTab->nCol+1;
aOp[3].p2 = pTab->nCol;
- pParse->nVar = 0;
- pParse->nMem = 1;
- pParse->nTab = 1;
- sqlite3VdbeMakeReady(v, pParse);
+ sParse.nVar = 0;
+ sParse.nMem = 1;
+ sParse.nTab = 1;
+ sqlite3VdbeMakeReady(v, &sParse);
}
}
@@ -86637,8 +86830,7 @@ blob_open_out:
}
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
- sqlite3ParserReset(pParse);
- sqlite3StackFree(db, pParse);
+ sqlite3ParserReset(&sParse);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
@@ -87632,7 +87824,7 @@ static int vdbeSorterCompareText(
}
if( res==0 ){
- if( pTask->pSorter->pKeyInfo->nField>1 ){
+ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
res = vdbeSorterCompareTail(
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
);
@@ -87701,7 +87893,7 @@ static int vdbeSorterCompareInt(
}
if( res==0 ){
- if( pTask->pSorter->pKeyInfo->nField>1 ){
+ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
res = vdbeSorterCompareTail(
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
);
@@ -87716,7 +87908,7 @@ static int vdbeSorterCompareInt(
/*
** Initialize the temporary index cursor just opened as a sorter cursor.
**
-** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField)
+** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nKeyField)
** to determine the number of fields that should be compared from the
** records being sorted. However, if the value passed as argument nField
** is non-zero and the sorter is able to guarantee a stable sort, nField
@@ -87769,7 +87961,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
assert( pCsr->pKeyInfo && pCsr->pBtx==0 );
assert( pCsr->eCurType==CURTYPE_SORTER );
- szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
+ szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
@@ -87781,8 +87973,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
pKeyInfo->db = 0;
if( nField && nWorker==0 ){
- pKeyInfo->nXField += (pKeyInfo->nField - nField);
- pKeyInfo->nField = nField;
+ pKeyInfo->nKeyField = nField;
}
pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
pSorter->nTask = nWorker + 1;
@@ -87810,11 +88001,9 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
mxCache = MIN(mxCache, SQLITE_MAX_PMASZ);
pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache);
- /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
- ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
- ** large heap allocations.
- */
- if( sqlite3GlobalConfig.pScratch==0 ){
+ /* Avoid large memory allocations if the application has requested
+ ** SQLITE_CONFIG_SMALL_MALLOC. */
+ if( sqlite3GlobalConfig.bSmallMalloc==0 ){
assert( pSorter->iMemory==0 );
pSorter->nMemory = pgsz;
pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz);
@@ -87822,7 +88011,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
}
}
- if( (pKeyInfo->nField+pKeyInfo->nXField)<13
+ if( pKeyInfo->nAllField<13
&& (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
){
pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
@@ -88137,7 +88326,7 @@ static int vdbeSortAllocUnpacked(SortSubtask *pTask){
if( pTask->pUnpacked==0 ){
pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo);
if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT;
- pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField;
+ pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nKeyField;
pTask->pUnpacked->errCode = 0;
}
return SQLITE_OK;
@@ -89661,7 +89850,8 @@ static int memjrnlRead(
int iChunkOffset;
FileChunk *pChunk;
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
if( (iAmt+iOfst)>p->endpoint.iOffset ){
return SQLITE_IOERR_SHORT_READ;
}
@@ -89780,7 +89970,8 @@ static int memjrnlWrite(
** 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 );
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
if( iOfst==0 && p->pFirst ){
assert( p->nChunkSize>iAmt );
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
@@ -89949,17 +90140,31 @@ SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){
sqlite3JournalOpen(0, 0, pJfd, 0, -1);
}
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#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
** in-memory-only journal file (i.e. is one that was opened with a +ve
-** nSpill parameter), and the underlying file has not yet been created,
-** create it now.
+** 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 *p){
+SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){
int rc = SQLITE_OK;
- if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
- rc = memjrnlCreateFile((MemJournal*)p);
+ MemJournal *p = (MemJournal*)pJfd;
+ if( p->pMethod==&MemJournalMethods && (
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ p->nSpill>0
+#else
+ /* While this appears to not be possible without ATOMIC_WRITE, the
+ ** paths are complex, so it seems prudent to leave the test in as
+ ** a NEVER(), in case our analysis is subtly flawed. */
+ NEVER(p->nSpill>0)
+#endif
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ || (p->flags & SQLITE_OPEN_MAIN_JOURNAL)
+#endif
+ )){
+ rc = memjrnlCreateFile(p);
}
return rc;
}
@@ -90026,18 +90231,22 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
int rc;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
- rc = pWalker->xExprCallback(pWalker, pExpr);
- if( rc ) return rc & WRC_Abort;
- if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
- if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
- assert( pExpr->x.pList==0 || pExpr->pRight==0 );
- if( pExpr->pRight ){
- if( walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
- }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
- }else if( pExpr->x.pList ){
- if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
+ while(1){
+ rc = pWalker->xExprCallback(pWalker, pExpr);
+ if( rc ) return rc & WRC_Abort;
+ if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
+ if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
+ assert( pExpr->x.pList==0 || pExpr->pRight==0 );
+ if( pExpr->pRight ){
+ pExpr = pExpr->pRight;
+ continue;
+ }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
+ }else if( pExpr->x.pList ){
+ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
+ }
}
+ break;
}
return WRC_Continue;
}
@@ -91105,12 +91314,10 @@ static int resolveCompoundOrderBy(
pOrderBy = pSelect->pOrderBy;
if( pOrderBy==0 ) return 0;
db = pParse->db;
-#if SQLITE_MAX_COLUMN
if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause");
return 1;
}
-#endif
for(i=0; i<pOrderBy->nExpr; i++){
pOrderBy->a[i].done = 0;
}
@@ -91202,12 +91409,10 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(
struct ExprList_item *pItem;
if( pOrderBy==0 || pParse->db->mallocFailed ) return 0;
-#if SQLITE_MAX_COLUMN
if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType);
return 1;
}
-#endif
pEList = pSelect->pEList;
assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
@@ -91808,6 +92013,11 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
** Return the collation sequence for the expression pExpr. If
** there is no defined collating sequence, return NULL.
**
+** See also: sqlite3ExprNNCollSeq()
+**
+** The sqlite3ExprNNCollSeq() works the same exact that it returns the
+** default collation if pExpr has no defined collation.
+**
** The collating sequence might be determined by a COLLATE operator
** or by the presence of a column with a defined collating sequence.
** COLLATE operators take first precedence. Left operands take
@@ -91873,6 +92083,32 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
}
/*
+** Return the collation sequence for the expression pExpr. If
+** there is no defined collating sequence, return a pointer to the
+** defautl collation sequence.
+**
+** See also: sqlite3ExprCollSeq()
+**
+** 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){
+ CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr);
+ if( p==0 ) p = pParse->db->pDfltColl;
+ assert( p!=0 );
+ return p;
+}
+
+/*
+** Return TRUE if the two expressions have equivalent collating sequences.
+*/
+SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){
+ CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1);
+ CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2);
+ return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0;
+}
+
+/*
** pExpr is an operand of a comparison operator. aff2 is the
** type affinity of the other operand. This routine returns the
** type affinity that should be used for the comparison operator.
@@ -92459,7 +92695,7 @@ SQLITE_PRIVATE Expr *sqlite3Expr(
){
Token x;
x.z = zToken;
- x.n = zToken ? sqlite3Strlen30(zToken) : 0;
+ x.n = sqlite3Strlen30(zToken);
return sqlite3ExprAlloc(db, op, &x, 0);
}
@@ -92986,10 +93222,9 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags)
Expr *pPriorSelectCol = 0;
assert( db!=0 );
if( p==0 ) return 0;
- pNew = sqlite3DbMallocRawNN(db,
- sizeof(*pNew)+sizeof(pNew->a[0])*(p->nExpr-1) );
+ pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p));
if( pNew==0 ) return 0;
- pNew->nAlloc = pNew->nExpr = p->nExpr;
+ pNew->nExpr = p->nExpr;
pItem = pNew->a;
pOldItem = p->a;
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
@@ -93143,6 +93378,13 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
** Add a new element to the end of an expression list. If pList is
** initially NULL, then create a new expression list.
**
+** The pList argument must be either NULL or a pointer to an ExprList
+** obtained from a prior call to sqlite3ExprListAppend(). This routine
+** may not be used with an ExprList obtained from sqlite3ExprListDup().
+** Reason: This routine assumes that the number of slots in pList->a[]
+** is a power of two. That is true for sqlite3ExprListAppend() returns
+** but is not necessarily true from the return value of sqlite3ExprListDup().
+**
** If a memory allocation error occurs, the entire list is freed and
** NULL is returned. If non-NULL is returned, then it is guaranteed
** that the new entry was successfully appended.
@@ -93161,16 +93403,14 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(
goto no_mem;
}
pList->nExpr = 0;
- pList->nAlloc = 1;
- }else if( pList->nExpr==pList->nAlloc ){
+ }else if( (pList->nExpr & (pList->nExpr-1))==0 ){
ExprList *pNew;
pNew = sqlite3DbRealloc(db, pList,
- sizeof(*pList)+(2*pList->nAlloc - 1)*sizeof(pList->a[0]));
+ sizeof(*pList)+(2*pList->nExpr - 1)*sizeof(pList->a[0]));
if( pNew==0 ){
goto no_mem;
}
pList = pNew;
- pList->nAlloc *= 2;
}
pItem = &pList->a[pList->nExpr++];
assert( offsetof(struct ExprList_item,zName)==sizeof(pItem->pExpr) );
@@ -93361,17 +93601,29 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){
int i;
u32 m = 0;
- if( pList ){
- for(i=0; i<pList->nExpr; i++){
- Expr *pExpr = pList->a[i].pExpr;
- assert( pExpr!=0 );
- m |= pExpr->flags;
- }
+ assert( pList!=0 );
+ for(i=0; i<pList->nExpr; i++){
+ Expr *pExpr = pList->a[i].pExpr;
+ assert( pExpr!=0 );
+ m |= pExpr->flags;
}
return m;
}
/*
+** This is a SELECT-node callback for the expression walker that
+** always "fails". By "fail" in this case, we mean set
+** pWalker->eCode to zero and abort.
+**
+** This callback is used by multiple expression walkers.
+*/
+SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){
+ UNUSED_PARAMETER(NotUsed);
+ pWalker->eCode = 0;
+ return WRC_Abort;
+}
+
+/*
** These routines are Walker callbacks used to check expressions to
** see if they are "constant" for some definition of constant. The
** Walker.eCode value determines the type of "constant" we are looking
@@ -93447,21 +93699,16 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
}
/* Fall through */
default:
- testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */
- testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */
+ testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail will disallow */
+ testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail will disallow */
return WRC_Continue;
}
}
-static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
- UNUSED_PARAMETER(NotUsed);
- pWalker->eCode = 0;
- return WRC_Abort;
-}
static int exprIsConst(Expr *p, int initFlag, int iCur){
Walker w;
w.eCode = initFlag;
w.xExprCallback = exprNodeIsConstant;
- w.xSelectCallback = selectNodeIsConstant;
+ w.xSelectCallback = sqlite3SelectWalkFail;
#ifdef SQLITE_DEBUG
w.xSelectCallback2 = sqlite3SelectWalkAssert2;
#endif
@@ -93515,8 +93762,8 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
for(i=0; i<pGroupBy->nExpr; i++){
Expr *p = pGroupBy->a[i].pExpr;
if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){
- CollSeq *pColl = sqlite3ExprCollSeq(pWalker->pParse, p);
- if( pColl==0 || sqlite3_stricmp("BINARY", pColl->zName)==0 ){
+ CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p);
+ if( sqlite3_stricmp("BINARY", pColl->zName)==0 ){
return WRC_Prune;
}
}
@@ -93584,7 +93831,7 @@ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){
Walker w;
w.eCode = 1;
w.xExprCallback = sqlite3ExprWalkNoop;
- w.xSelectCallback = selectNodeIsConstant;
+ w.xSelectCallback = sqlite3SelectWalkFail;
#ifdef SQLITE_DEBUG
w.xSelectCallback2 = sqlite3SelectWalkAssert2;
#endif
@@ -93657,8 +93904,8 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
case TK_BLOB:
return 0;
case TK_COLUMN:
- assert( p->pTab!=0 );
return ExprHasProperty(p, EP_CanBeNull) ||
+ p->pTab==0 || /* Reference to column of index on expression */
(p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0);
default:
return 1;
@@ -94320,7 +94567,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
/* Loop through each expression in <exprlist>. */
r1 = sqlite3GetTempReg(pParse);
r2 = sqlite3GetTempReg(pParse);
- if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
+ if( isRowid ) sqlite3VdbeAddOp4(v, OP_Blob, 0, r2, 0, "", P4_STATIC);
for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
Expr *pE2 = pItem->pExpr;
int iValToIns;
@@ -94748,7 +94995,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
const char *z = pExpr->u.zToken;
assert( z!=0 );
c = sqlite3DecOrHexToI64(z, &value);
- if( c==1 || (c==2 && !negFlag) || (negFlag && value==SMALLEST_INT64)){
+ if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){
#ifdef SQLITE_OMIT_FLOATING_POINT
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
#else
@@ -94762,7 +95009,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
}
#endif
}else{
- if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
+ if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; }
sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
}
}
@@ -95917,7 +96164,9 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ
** Generate code that pushes the value of every element of the given
** expression list into a sequence of registers beginning at target.
**
-** Return the number of elements evaluated.
+** Return the number of elements evaluated. The number returned will
+** usually be pList->nExpr but might be reduced if SQLITE_ECEL_OMITREF
+** is defined.
**
** The SQLITE_ECEL_DUP flag prevents the arguments from being
** filled using OP_SCopy. OP_Copy must be used instead.
@@ -95928,6 +96177,8 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ
** The SQLITE_ECEL_REF flag means that expressions in the list with
** ExprList.a[].u.x.iOrderByCol>0 have already been evaluated and stored
** in registers at srcReg, and so the value can be copied from there.
+** If SQLITE_ECEL_OMITREF is also set, then the values with u.x.iOrderByCol>0
+** are simply omitted rather than being copied from srcReg.
*/
SQLITE_PRIVATE int sqlite3ExprCodeExprList(
Parse *pParse, /* Parsing context */
@@ -97361,9 +97612,9 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
char *zWhere = 0; /* Where clause to locate temp triggers */
#endif
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
- int savedDbFlags; /* Saved value of db->flags */
+ u32 savedDbFlags; /* Saved value of db->mDbFlags */
- savedDbFlags = db->flags;
+ savedDbFlags = db->mDbFlags;
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
assert( pSrc->nSrc==1 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
@@ -97372,7 +97623,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zDbSName;
- db->flags |= SQLITE_PreferBuiltin;
+ db->mDbFlags |= DBFLAG_PreferBuiltin;
/* Get a NULL terminated version of the new table name. */
zName = sqlite3NameFromToken(db, pName);
@@ -97537,7 +97788,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
exit_rename_table:
sqlite3SrcListDelete(db, pSrc);
sqlite3DbFree(db, zName);
- db->flags = savedDbFlags;
+ db->mDbFlags = savedDbFlags;
}
/*
@@ -97638,11 +97889,11 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
if( zCol ){
char *zEnd = &zCol[pColDef->n-1];
- int savedDbFlags = db->flags;
+ u32 savedDbFlags = db->mDbFlags;
while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
*zEnd-- = '\0';
}
- db->flags |= SQLITE_PreferBuiltin;
+ db->mDbFlags |= DBFLAG_PreferBuiltin;
sqlite3NestedParse(pParse,
"UPDATE \"%w\".%s SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
@@ -97651,7 +97902,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
zTab
);
sqlite3DbFree(db, zCol);
- db->flags = savedDbFlags;
+ db->mDbFlags = savedDbFlags;
}
/* Make sure the schema version is at least 3. But do not upgrade
@@ -99776,10 +100027,6 @@ static void attachFunc(
);
goto attach_error;
}
- if( !db->autoCommit ){
- zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction");
- goto attach_error;
- }
for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zDbSName;
assert( z && zName );
@@ -99971,11 +100218,6 @@ static void detachFunc(
sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
goto detach_error;
}
- if( !db->autoCommit ){
- sqlite3_snprintf(sizeof(zErr), zErr,
- "cannot DETACH database within transaction");
- goto detach_error;
- }
if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){
sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
goto detach_error;
@@ -100388,11 +100630,9 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(
#endif
);
if( rc==SQLITE_DENY ){
- if( db->nDb>2 || iDb!=0 ){
- sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol);
- }else{
- sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol);
- }
+ char *z = sqlite3_mprintf("%s.%s", zTab, zCol);
+ if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z);
+ sqlite3ErrorMsg(pParse, "access to %z is prohibited", z);
pParse->rc = SQLITE_AUTH;
}else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){
sqliteAuthBadReturnCode(pParse);
@@ -101025,7 +101265,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char
}
freeIndex(db, pIndex);
}
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
/*
@@ -101060,28 +101300,26 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){
/*
** Reset the schema for the database at index iDb. Also reset the
-** TEMP schema.
+** TEMP schema. The reset is deferred if db->nSchemaLock is not zero.
+** Deferred resets may be run by calling with iDb<0.
*/
SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
- Db *pDb;
+ int i;
assert( iDb<db->nDb );
- /* Case 1: Reset the single schema identified by iDb */
- pDb = &db->aDb[iDb];
- assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- assert( pDb->pSchema!=0 );
- sqlite3SchemaClear(pDb->pSchema);
+ if( iDb>=0 ){
+ assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
+ DbSetProperty(db, iDb, DB_ResetWanted);
+ DbSetProperty(db, 1, DB_ResetWanted);
+ }
- /* If any database other than TEMP is reset, then also reset TEMP
- ** since TEMP might be holding triggers that reference tables in the
- ** other database.
- */
- if( iDb!=1 ){
- pDb = &db->aDb[1];
- assert( pDb->pSchema!=0 );
- sqlite3SchemaClear(pDb->pSchema);
+ if( db->nSchemaLock==0 ){
+ for(i=0; i<db->nDb; i++){
+ if( DbHasProperty(db, i, DB_ResetWanted) ){
+ sqlite3SchemaClear(db->aDb[i].pSchema);
+ }
+ }
}
- return;
}
/*
@@ -101091,13 +101329,14 @@ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
int i;
sqlite3BtreeEnterAll(db);
+ assert( db->nSchemaLock==0 );
for(i=0; i<db->nDb; i++){
Db *pDb = &db->aDb[i];
if( pDb->pSchema ){
sqlite3SchemaClear(pDb->pSchema);
}
}
- db->flags &= ~SQLITE_InternChanges;
+ db->mDbFlags &= ~DBFLAG_SchemaChange;
sqlite3VtabUnlockList(db);
sqlite3BtreeLeaveAll(db);
sqlite3CollapseDatabaseArray(db);
@@ -101107,7 +101346,7 @@ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
** This routine is called when a commit occurs.
*/
SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){
- db->flags &= ~SQLITE_InternChanges;
+ db->mDbFlags &= ~DBFLAG_SchemaChange;
}
/*
@@ -101145,13 +101384,16 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
*/
static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
Index *pIndex, *pNext;
- TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */
+#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. */
- TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ?
- db->lookaside.nOut : 0 );
+ int nLookaside = 0;
+ if( db && (pTable->tabFlags & TF_Ephemeral)==0 ){
+ nLookaside = sqlite3LookasideUsed(db, 0);
+ }
+#endif
/* Delete all indices associated with this table. */
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
@@ -101185,7 +101427,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
sqlite3DbFree(db, pTable);
/* Verify that no lookaside memory was used by schema tables */
- assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
+ assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) );
}
SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Do not delete the table until the reference count reaches zero. */
@@ -101211,7 +101453,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char
pDb = &db->aDb[iDb];
p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
sqlite3DeleteTable(db, p);
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
/*
@@ -101324,7 +101566,8 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
return -1;
}
}else{
- assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0);
+ assert( db->init.iDb==0 || db->init.busy
+ || (db->mDbFlags & DBFLAG_Vacuum)!=0);
iDb = db->init.iDb;
*pUnqual = pName1;
}
@@ -101556,7 +101799,8 @@ SQLITE_PRIVATE void sqlite3StartTable(
}else
#endif
{
- pParse->addrCrTab = sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
+ pParse->addrCrTab =
+ sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
}
sqlite3OpenMasterTable(pParse, iDb);
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
@@ -101605,12 +101849,10 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
Column *pCol;
sqlite3 *db = pParse->db;
if( (p = pParse->pNewTable)==0 ) return;
-#if SQLITE_MAX_COLUMN
if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName);
return;
}
-#endif
z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
if( z==0 ) return;
memcpy(z, pName->z, pName->n);
@@ -102216,9 +102458,8 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
** Changes include:
**
** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
-** (2) Convert the OP_CreateTable into an OP_CreateIndex. There is
-** no rowid btree for a WITHOUT ROWID. Instead, the canonical
-** data storage is a covering index btree.
+** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY
+** into BTREE_BLOBKEY.
** (3) Bypass the creation of the sqlite_master table entry
** for the PRIMARY KEY as the primary key index is now
** identified by the sqlite_master table entry of the table itself.
@@ -102226,7 +102467,7 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
** schema to the rootpage from the main table.
** (5) Add all table columns to the PRIMARY KEY Index object
** so that the PRIMARY KEY is a covering index. The surplus
-** columns are part of KeyInfo.nXField and are not used for
+** columns are part of KeyInfo.nAllField and are not used for
** sorting or lookup or uniqueness checks.
** (6) Replace the rowid tail on all automatically generated UNIQUE
** indices with the PRIMARY KEY columns.
@@ -102255,13 +102496,12 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
** virtual tables */
if( IN_DECLARE_VTAB ) return;
- /* Convert the OP_CreateTable opcode that would normally create the
- ** root-page for the table into an OP_CreateIndex opcode. The index
- ** created will become the PRIMARY KEY index.
+ /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
+ ** into BTREE_BLOBKEY.
*/
if( pParse->addrCrTab ){
assert( v );
- sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex);
+ sqlite3VdbeChangeP3(v, pParse->addrCrTab, BTREE_BLOBKEY);
}
/* Locate the PRIMARY KEY index. Or, if this table was originally
@@ -102601,7 +102841,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
return;
}
pParse->pNewTable = 0;
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
#ifndef SQLITE_OMIT_ALTERTABLE
if( !p->pSelect ){
@@ -102700,6 +102940,9 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
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;
+#endif
#ifndef SQLITE_OMIT_AUTHORIZATION
sqlite3_xauth xAuth; /* Saved xAuth pointer */
#endif
@@ -102707,8 +102950,11 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable );
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( sqlite3VtabCallConnect(pParse, pTable) ){
- return SQLITE_ERROR;
+ db->nSchemaLock++;
+ rc = sqlite3VtabCallConnect(pParse, pTable);
+ db->nSchemaLock--;
+ if( rc ){
+ return 1;
}
if( IsVirtual(pTable) ) return 0;
#endif
@@ -102904,14 +103150,6 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
** is also added (this can happen with an auto-vacuum database).
*/
static void destroyTable(Parse *pParse, Table *pTab){
-#ifdef SQLITE_OMIT_AUTOVACUUM
- Index *pIdx;
- int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
- destroyRootPage(pParse, pTab->tnum, iDb);
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- destroyRootPage(pParse, pIdx->tnum, iDb);
- }
-#else
/* 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
@@ -102954,7 +103192,6 @@ static void destroyTable(Parse *pParse, Table *pTab){
iDestroyed = iLargest;
}
}
-#endif
}
/*
@@ -103381,7 +103618,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
addr2 = sqlite3VdbeCurrentAddr(v);
}
sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
- sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
+ sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
sqlite3ReleaseTempReg(pParse, regRecord);
@@ -103870,7 +104107,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
sqlite3OomFault(db);
goto exit_create_index;
}
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
if( pTblName!=0 ){
pIndex->tnum = db->init.newTnum;
}
@@ -103906,7 +104143,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
** 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);
- sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem);
+ sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
/* Gather the complete text of the CREATE INDEX statement into
** the zStmt variable
@@ -104428,8 +104665,10 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
*/
SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
assert( pIndexedBy!=0 );
- if( p && ALWAYS(p->nSrc>0) ){
- struct SrcList_item *pItem = &p->a[p->nSrc-1];
+ if( p && pIndexedBy->n>0 ){
+ struct SrcList_item *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 );
@@ -104439,7 +104678,7 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI
pItem->fg.notIndexed = 1;
}else{
pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
- pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0);
+ pItem->fg.isIndexedBy = 1;
}
}
}
@@ -105364,7 +105603,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
/* If no match is found, search the built-in functions.
**
- ** If the SQLITE_PreferBuiltin flag is set, then search the built-in
+ ** If the DBFLAG_PreferBuiltin flag is set, then search the built-in
** functions even if a prior app-defined function was found. And give
** priority to built-in functions.
**
@@ -105374,7 +105613,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
** 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->flags & SQLITE_PreferBuiltin)!=0) ){
+ if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){
bestScore = 0;
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
p = functionSearch(h, zName);
@@ -105447,8 +105686,8 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
pSchema->pSeqTab = 0;
if( pSchema->schemaFlags & DB_SchemaLoaded ){
pSchema->iGeneration++;
- pSchema->schemaFlags &= ~DB_SchemaLoaded;
}
+ pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted);
}
/*
@@ -105980,7 +106219,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}
}else if( pPk ){
addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
+ if( IsVirtual(pTab) ){
+ sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
+ }
assert( nKey==0 ); /* OP_Found will use a composite key */
}else{
addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
@@ -107251,7 +107494,8 @@ static void likeFunc(
#ifdef SQLITE_TEST
sqlite3_like_count++;
#endif
- sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH);
+ sqlite3_result_int(context,
+ patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH);
}
}
@@ -108092,9 +108336,14 @@ 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
-** return TRUE. If the function is not a LIKE-style function then
-** return FALSE.
+** 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
+** LIKE-style function then return FALSE.
+**
+** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE
+** operator if c is a string literal that is exactly one byte in length.
+** That one byte is stored in aWc[3]. aWc[3] is set to zero if there is
+** no ESCAPE clause.
**
** *pIsNocase is set to true if uppercase and lowercase are equivalent for
** the function (default for LIKE). If the function makes the distinction
@@ -108103,17 +108352,26 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
*/
SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
- if( pExpr->op!=TK_FUNCTION
- || !pExpr->x.pList
- || pExpr->x.pList->nExpr!=2
- ){
+ int nExpr;
+ if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0);
+ nExpr = pExpr->x.pList->nExpr;
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
+ if( nExpr<3 ){
+ aWc[3] = 0;
+ }else{
+ Expr *pEscape = pExpr->x.pList->a[2].pExpr;
+ char *zEscape;
+ if( pEscape->op!=TK_STRING ) return 0;
+ zEscape = pEscape->u.zToken;
+ if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
+ aWc[3] = zEscape[0];
+ }
/* The memcpy() statement assumes that the wildcard characters are
** the first three statements in the compareInfo structure. The
@@ -109913,7 +110171,7 @@ static int autoIncBegin(
){
int memId = 0; /* Register holding maximum rowid */
if( (pTab->tabFlags & TF_Autoincrement)!=0
- && (pParse->db->flags & SQLITE_Vacuum)==0
+ && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0
){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
AutoincInfo *pInfo;
@@ -110171,7 +110429,6 @@ SQLITE_PRIVATE void sqlite3Insert(
){
sqlite3 *db; /* The main database structure */
Table *pTab; /* The table to insert into. aka TABLE */
- char *zTab; /* Name of the table into which we are inserting */
int i, j; /* Loop counters */
Vdbe *v; /* Generate code into this virtual machine */
Index *pIdx; /* For looping over indices of the table */
@@ -110227,8 +110484,6 @@ SQLITE_PRIVATE void sqlite3Insert(
/* Locate the table into which we will be inserting new information.
*/
assert( pTabList->nSrc==1 );
- zTab = pTabList->a[0].zName;
- if( NEVER(zTab==0) ) goto insert_cleanup;
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ){
goto insert_cleanup;
@@ -111745,7 +112000,7 @@ static int xferOptimization(
Column *pDestCol = &pDest->aCol[i];
Column *pSrcCol = &pSrc->aCol[i];
#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
- if( (db->flags & SQLITE_Vacuum)==0
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0
&& (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
){
return 0; /* Neither table may have __hidden__ columns */
@@ -111821,15 +112076,15 @@ static int xferOptimization(
regRowid = sqlite3GetTempReg(pParse);
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
assert( HasRowid(pDest) || destHasUniqueIdx );
- if( (db->flags & SQLITE_Vacuum)==0 && (
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (
(pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
|| destHasUniqueIdx /* (2) */
|| (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */
)){
/* In some circumstances, we are able to run the xfer optimization
** only if the destination table is initially empty. Unless the
- ** SQLITE_Vacuum flag is set, this block generates code to make
- ** that determination. If SQLITE_Vacuum is set, then the destination
+ ** DBFLAG_Vacuum flag is set, this block generates code to make
+ ** that determination. If DBFLAG_Vacuum is set, then the destination
** table is always empty.
**
** Conditions under which the destination must be empty:
@@ -111865,8 +112120,8 @@ static int xferOptimization(
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
}
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
- if( db->flags & SQLITE_Vacuum ){
- sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
+ if( db->mDbFlags & DBFLAG_Vacuum ){
+ sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|
OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
}else{
@@ -111897,13 +112152,13 @@ static int xferOptimization(
VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
- if( db->flags & SQLITE_Vacuum ){
+ 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
** order. In this case, instead of seeking within the b-tree as part
- ** of every OP_IdxInsert opcode, an OP_Last is added before the
+ ** 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
** should be inserted. This is faster.
**
@@ -111918,7 +112173,7 @@ static int xferOptimization(
}
if( i==pSrcIdx->nColumn ){
idxInsFlags = OPFLAG_USESEEKRESULT;
- sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
+ sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
}
}
if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
@@ -112249,7 +112504,7 @@ struct sqlite3_api_routines {
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
- char * (*snprintf)(int,char*,const char*,...);
+ char * (*xsnprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
@@ -112361,7 +112616,7 @@ struct sqlite3_api_routines {
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
- char *(*vsnprintf)(int,char*,const char*,va_list);
+ char *(*xvsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
/* Version 3.8.7 and later */
int (*auto_extension)(void(*)(void));
@@ -112533,7 +112788,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
-#define sqlite3_snprintf sqlite3_api->snprintf
+#define sqlite3_snprintf sqlite3_api->xsnprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
@@ -112557,7 +112812,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
-#define sqlite3_vsnprintf sqlite3_api->vsnprintf
+#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
@@ -112633,7 +112888,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
-#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
+#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
/* Version 3.8.7 and later */
#define sqlite3_auto_extension sqlite3_api->auto_extension
@@ -114434,16 +114689,16 @@ static const PragmaName *pragmaLocate(const char *zName){
/*
** Helper subroutine for PRAGMA integrity_check:
**
-** Generate code to output a single-column result row with the result
-** held in register regResult. Decrement the result count and halt if
-** the maximum number of result rows have been issued.
+** Generate code to output a single-column result row with a value of the
+** string held in register 3. Decrement the result count in register 1
+** and halt if the maximum number of result rows have been issued.
*/
-static int integrityCheckResultRow(Vdbe *v, int regResult){
+static int integrityCheckResultRow(Vdbe *v){
int addr;
- sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 1);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1);
VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
+ sqlite3VdbeAddOp0(v, OP_Halt);
return addr;
}
@@ -115391,13 +115646,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){
sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}
for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){
p = (FuncDef*)sqliteHashData(j);
sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 0);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}
break;
@@ -115409,7 +115662,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
for(j=sqliteHashFirst(&db->aModule); j; j=sqliteHashNext(j)){
Module *pMod = (Module*)sqliteHashData(j);
sqlite3VdbeMultiLoad(v, 1, "s", pMod->zName);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}
break;
@@ -115419,7 +115671,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
int i;
for(i=0; i<ArraySize(aPragmaName); i++){
sqlite3VdbeMultiLoad(v, 1, "s", aPragmaName[i].zName);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}
break;
@@ -115645,12 +115896,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){
- HashElem *x;
- Hash *pTbls;
- int *aRoot;
- int cnt = 0;
- int mxIdx = 0;
- int nIdx;
+ HashElem *x; /* For looping over tables in the schema */
+ Hash *pTbls; /* Set of all tables in the schema */
+ int *aRoot; /* Array of root page numbers of all btrees */
+ int cnt = 0; /* Number of entries in aRoot[] */
+ int mxIdx = 0; /* Maximum number of indexes for any table */
if( OMIT_TEMPDB && i==1 ) continue;
if( iDb>=0 && i!=iDb ) continue;
@@ -115665,8 +115915,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
assert( sqlite3SchemaMutexHeld(db, i, 0) );
pTbls = &db->aDb[i].pSchema->tblHash;
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
- Table *pTab = sqliteHashData(x);
- Index *pIdx;
+ Table *pTab = sqliteHashData(x); /* Current table */
+ Index *pIdx; /* An index on pTab */
+ int nIdx; /* Number of indexes on pTab */
if( HasRowid(pTab) ) cnt++;
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
if( nIdx>mxIdx ) mxIdx = nIdx;
@@ -115694,9 +115945,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName),
P4_DYNAMIC);
- sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
- sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
- integrityCheckResultRow(v, 2);
+ sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3);
+ integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly.
@@ -115710,16 +115960,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
int r1 = -1;
if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
- if( pTab->pCheck==0
- && (pTab->tabFlags & TF_HasNotNull)==0
- && (pTab->pIndex==0 || isQuick)
- ){
- continue; /* No additional checks needed for this table */
- }
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
sqlite3ExprCacheClear(pParse);
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
+ */
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
@@ -115740,7 +115987,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pTab->aCol[j].zName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- integrityCheckResultRow(v, 3);
+ integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, jmp2);
}
/* Verify CHECK constraints */
@@ -115763,57 +116010,62 @@ SQLITE_PRIVATE void sqlite3Pragma(
zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
pTab->zName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- integrityCheckResultRow(v, 3);
+ integrityCheckResultRow(v);
sqlite3VdbeResolveLabel(v, addrCkOk);
sqlite3ExprCachePop(pParse);
}
sqlite3ExprListDelete(db, pCheck);
}
- /* Validate index entries for the current row */
- for(j=0, pIdx=pTab->pIndex; pIdx && !isQuick; pIdx=pIdx->pNext, j++){
- int jmp2, jmp3, jmp4, jmp5;
- int ckUniq = sqlite3VdbeMakeLabel(v);
- if( pPk==pIdx ) continue;
- r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
- pPrior, r1);
- pPrior = pIdx;
- sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */
- /* Verify that an index entry exists for the current table row */
- jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
- pIdx->nColumn); VdbeCoverage(v);
- sqlite3VdbeLoadString(v, 3, "row ");
- sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
- sqlite3VdbeLoadString(v, 4, " missing from index ");
- sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
- jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
- sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
- jmp4 = integrityCheckResultRow(v, 3);
- sqlite3VdbeJumpHere(v, jmp2);
- /* 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(v);
- int jmp6;
- int kk;
- for(kk=0; kk<pIdx->nKeyCol; kk++){
- int iCol = pIdx->aiColumn[kk];
- assert( iCol!=XN_ROWID && iCol<pTab->nCol );
- if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
- sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
- VdbeCoverage(v);
+ if( !isQuick ){ /* Omit the remaining tests for quick_check */
+ /* Sanity check on record header decoding */
+ sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3);
+ sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ /* Validate index entries for the current row */
+ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
+ int jmp2, jmp3, jmp4, jmp5;
+ int ckUniq = sqlite3VdbeMakeLabel(v);
+ if( pPk==pIdx ) continue;
+ r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
+ pPrior, r1);
+ pPrior = pIdx;
+ sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */
+ /* Verify that an index entry exists for the current table row */
+ jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
+ pIdx->nColumn); VdbeCoverage(v);
+ sqlite3VdbeLoadString(v, 3, "row ");
+ sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
+ sqlite3VdbeLoadString(v, 4, " missing from index ");
+ sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
+ jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
+ sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
+ jmp4 = integrityCheckResultRow(v);
+ sqlite3VdbeJumpHere(v, jmp2);
+ /* 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(v);
+ int jmp6;
+ int kk;
+ for(kk=0; kk<pIdx->nKeyCol; kk++){
+ int iCol = pIdx->aiColumn[kk];
+ assert( iCol!=XN_ROWID && iCol<pTab->nCol );
+ if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
+ sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
+ VdbeCoverage(v);
+ }
+ jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
+ sqlite3VdbeGoto(v, uniqOk);
+ sqlite3VdbeJumpHere(v, jmp6);
+ sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
+ pIdx->nKeyCol); VdbeCoverage(v);
+ sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
+ sqlite3VdbeGoto(v, jmp5);
+ sqlite3VdbeResolveLabel(v, uniqOk);
}
- jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
- sqlite3VdbeGoto(v, uniqOk);
- sqlite3VdbeJumpHere(v, jmp6);
- sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
- pIdx->nKeyCol); VdbeCoverage(v);
- sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
- sqlite3VdbeGoto(v, jmp5);
- sqlite3VdbeResolveLabel(v, uniqOk);
+ sqlite3VdbeJumpHere(v, jmp4);
+ sqlite3ResolvePartIdxLabel(pParse, jmp3);
}
- sqlite3VdbeJumpHere(v, jmp4);
- sqlite3ResolvePartIdxLabel(pParse, jmp3);
}
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, loopTop-1);
@@ -115825,9 +116077,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
- sqlite3VdbeLoadString(v, 3, pIdx->zName);
- sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
- integrityCheckResultRow(v, 7);
+ sqlite3VdbeLoadString(v, 4, pIdx->zName);
+ sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
+ integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
}
}
@@ -115841,6 +116093,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
{ OP_IfNotZero, 1, 4, 0}, /* 1 */
{ OP_String8, 0, 3, 0}, /* 2 */
{ OP_ResultRow, 3, 1, 0}, /* 3 */
+ { OP_Halt, 0, 0, 0}, /* 4 */
+ { OP_String8, 0, 3, 0}, /* 5 */
+ { OP_Goto, 0, 3, 0}, /* 6 */
};
VdbeOp *aOp;
@@ -115849,7 +116104,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
aOp[0].p2 = 1-mxErr;
aOp[2].p4type = P4_STATIC;
aOp[2].p4.z = "ok";
+ aOp[5].p4type = P4_STATIC;
+ aOp[5].p4.z = (char*)sqlite3ErrStr(SQLITE_CORRUPT);
}
+ sqlite3VdbeChangeP3(v, 0, sqlite3VdbeCurrentAddr(v)-2);
}
}
break;
@@ -116729,7 +116987,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
rc = db->errCode;
assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = saved_iDb;
- assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 );
+ assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 );
if( SQLITE_OK!=rc ){
if( db->init.orphanTrigger ){
assert( iDb==1 );
@@ -116794,6 +117052,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
assert( sqlite3_mutex_held(db->mutex) );
assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
+ db->init.busy = 1;
+
/* Construct the in-memory representation schema tables (sqlite_master or
** sqlite_temp_master) by invoking the parser directly. The appropriate
** table name will be inserted automatically by the parser so we can just
@@ -116802,7 +117062,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
azArg[0] = zMasterName = SCHEMA_TABLE(iDb);
azArg[1] = "1";
azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
- "rootpage integer,sql text)";
+ "rootpage int,sql text)";
azArg[3] = 0;
initData.db = db;
initData.iDb = iDb;
@@ -116818,10 +117078,10 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
*/
pDb = &db->aDb[iDb];
if( pDb->pBt==0 ){
- if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){
- DbSetProperty(db, 1, DB_SchemaLoaded);
- }
- return SQLITE_OK;
+ assert( iDb==1 );
+ DbSetProperty(db, 1, DB_SchemaLoaded);
+ rc = SQLITE_OK;
+ goto error_out;
}
/* If there is not already a read-only (or read-write) transaction opened
@@ -116980,9 +117240,13 @@ initone_error_out:
sqlite3BtreeLeave(pDb->pBt);
error_out:
- if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
- sqlite3OomFault(db);
+ if( rc ){
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
+ sqlite3OomFault(db);
+ }
+ sqlite3ResetOneSchema(db, iDb);
}
+ db->init.busy = 0;
return rc;
}
@@ -116998,42 +117262,29 @@ error_out:
*/
SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int i, rc;
- int commit_internal = !(db->flags&SQLITE_InternChanges);
+ int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);
assert( sqlite3_mutex_held(db->mutex) );
assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
assert( db->init.busy==0 );
- rc = SQLITE_OK;
- db->init.busy = 1;
ENC(db) = SCHEMA_ENC(db);
- for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
- if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
- rc = sqlite3InitOne(db, i, pzErrMsg);
- if( rc ){
- sqlite3ResetOneSchema(db, i);
- }
+ assert( db->nDb>0 );
+ /* Do the main schema first */
+ if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
+ rc = sqlite3InitOne(db, 0, pzErrMsg);
+ if( rc ) return rc;
}
-
- /* Once all the other databases have been initialized, load the schema
- ** for the TEMP database. This is loaded last, as the TEMP database
- ** schema may contain references to objects in other databases.
- */
-#ifndef SQLITE_OMIT_TEMPDB
- assert( db->nDb>1 );
- if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
- rc = sqlite3InitOne(db, 1, pzErrMsg);
- if( rc ){
- sqlite3ResetOneSchema(db, 1);
+ /* All other schemas after the main schema. The "temp" schema must be last */
+ for(i=db->nDb-1; i>0; i--){
+ if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
+ rc = sqlite3InitOne(db, i, pzErrMsg);
+ if( rc ) return rc;
}
}
-#endif
-
- db->init.busy = 0;
- if( rc==SQLITE_OK && commit_internal ){
+ if( commit_internal ){
sqlite3CommitInternalChanges(db);
}
-
- return rc;
+ return SQLITE_OK;
}
/*
@@ -117138,16 +117389,14 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
** Free all memory allocations in the pParse object
*/
SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){
- if( 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;
- }
- pParse->disableLookaside = 0;
+ 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;
}
+ pParse->disableLookaside = 0;
}
/*
@@ -117333,6 +117582,7 @@ static int sqlite3LockAndPrepare(
sqlite3BtreeEnterAll(db);
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
if( rc==SQLITE_SCHEMA ){
+ sqlite3ResetOneSchema(db, -1);
sqlite3_finalize(*ppStmt);
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
}
@@ -117626,7 +117876,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
sqlite3ExprListDelete(db, p->pOrderBy);
sqlite3ExprDelete(db, p->pLimit);
sqlite3ExprDelete(db, p->pOffset);
- if( p->pWith ) sqlite3WithDelete(db, p->pWith);
+ if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
if( bFree ) sqlite3DbFreeNN(db, p);
p = pPrior;
bFree = 1;
@@ -117669,7 +117919,8 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
pNew = &standin;
}
if( pEList==0 ){
- pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(pParse->db,TK_ASTERISK,0));
+ pEList = sqlite3ExprListAppend(pParse, 0,
+ sqlite3Expr(pParse->db,TK_ASTERISK,0));
}
pNew->pEList = pEList;
pNew->op = TK_SELECT;
@@ -117693,7 +117944,8 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
pNew->pLimit = pLimit;
pNew->pOffset = pOffset;
pNew->pWith = 0;
- assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || pParse->db->mallocFailed!=0 );
+ assert( pOffset==0 || pLimit!=0 || pParse->nErr>0
+ || pParse->db->mallocFailed!=0 );
if( pParse->db->mallocFailed ) {
clearSelect(pParse->db, pNew, pNew!=&standin);
pNew = 0;
@@ -117720,7 +117972,7 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){
** Delete the given Select structure and all of its substructures.
*/
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
- if( p ) clearSelect(db, p, 1);
+ if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
}
/*
@@ -117961,11 +118213,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
pLeft = &pSrc->a[0];
pRight = &pLeft[1];
for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
- Table *pLeftTab = pLeft->pTab;
Table *pRightTab = pRight->pTab;
int isOuter;
- if( NEVER(pLeftTab==0 || pRightTab==0) ) continue;
+ if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
isOuter = (pRight->fg.jointype & JT_OUTER)!=0;
/* When the NATURAL keyword is present, add WHERE clause terms for
@@ -118113,11 +118364,11 @@ static void pushOntoSorter(
if( pParse->db->mallocFailed ) return;
pOp->p2 = nKey + nData;
pKI = pOp->p4.pKeyInfo;
- memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
+ memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
- testcase( pKI->nXField>2 );
+ testcase( pKI->nAllField > pKI->nKeyField+2 );
pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
- pKI->nXField-1);
+ pKI->nAllField-pKI->nKeyField-1);
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
@@ -118215,16 +118466,15 @@ static void codeDistinct(
** This routine generates the code for the inside of the inner loop
** of a SELECT.
**
-** If srcTab is negative, then the pEList expressions
+** 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 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(
Parse *pParse, /* The parser context */
Select *p, /* The complete select statement being coded */
- ExprList *pEList, /* List of values being extracted */
- int srcTab, /* Pull data from this table */
+ int srcTab, /* Pull data from this table if non-negative */
SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */
DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
SelectDest *pDest, /* How to dispose of the results */
@@ -118248,7 +118498,7 @@ static void selectInnerLoop(
int regOrig; /* Start of memory holding full result (or 0) */
assert( v );
- assert( pEList!=0 );
+ assert( p->pEList!=0 );
hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
if( pSort && pSort->pOrderBy==0 ) pSort = 0;
if( pSort==0 && !hasDistinct ){
@@ -118258,7 +118508,7 @@ static void selectInnerLoop(
/* Pull the requested columns.
*/
- nResultCol = pEList->nExpr;
+ nResultCol = p->pEList->nExpr;
if( pDest->iSdst==0 ){
if( pSort ){
@@ -118281,7 +118531,7 @@ static void selectInnerLoop(
if( srcTab>=0 ){
for(i=0; i<nResultCol; i++){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
- VdbeComment((v, "%s", pEList->a[i].zName));
+ VdbeComment((v, "%s", p->pEList->a[i].zName));
}
}else if( eDest!=SRT_Exists ){
/* If the destination is an EXISTS(...) expression, the actual
@@ -118294,24 +118544,25 @@ static void selectInnerLoop(
ecelFlags = 0;
}
if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab && eDest!=SRT_Table ){
- /* For each expression in pEList that is a copy of an expression in
+ /* 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
** expression within the sort-key that pushOntoSorter() will generate.
- ** This allows the pEList field to be omitted from the sorted record,
+ ** This allows the p->pEList field to be omitted from the sorted record,
** saving space and CPU cycles. */
ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF);
for(i=pSort->nOBSat; i<pSort->pOrderBy->nExpr; i++){
int j;
if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){
- pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat;
+ p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat;
}
}
regOrig = 0;
assert( eDest==SRT_Set || eDest==SRT_Mem
|| eDest==SRT_Coroutine || eDest==SRT_Output );
}
- nResultCol = sqlite3ExprCodeExprList(pParse,pEList,regResult,0,ecelFlags);
+ nResultCol = sqlite3ExprCodeExprList(pParse,p->pEList,regResult,
+ 0,ecelFlags);
}
/* If the DISTINCT keyword was present on the SELECT statement
@@ -118343,7 +118594,7 @@ static void selectInnerLoop(
iJump = sqlite3VdbeCurrentAddr(v) + nResultCol;
for(i=0; i<nResultCol; i++){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr);
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr);
if( i<nResultCol-1 ){
sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i);
VdbeCoverage(v);
@@ -118586,8 +118837,8 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
if( p ){
p->aSortOrder = (u8*)&p->aColl[N+X];
- p->nField = (u16)N;
- p->nXField = (u16)X;
+ p->nKeyField = (u16)N;
+ p->nAllField = (u16)(N+X);
p->enc = ENC(db);
p->db = db;
p->nRef = 1;
@@ -118661,10 +118912,7 @@ static KeyInfo *keyInfoFromExprList(
if( pInfo ){
assert( sqlite3KeyInfoIsWriteable(pInfo) );
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
- CollSeq *pColl;
- pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- pInfo->aColl[i-iStart] = pColl;
+ pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr);
pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
}
}
@@ -118914,23 +119162,23 @@ static void generateSortTail(
** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used.
*/
#ifdef SQLITE_ENABLE_COLUMN_METADATA
-# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
+# define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E)
#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
-# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
+# define columnType(A,B,C,D,E) columnTypeImpl(A,B)
#endif
static const char *columnTypeImpl(
NameContext *pNC,
+#ifndef SQLITE_ENABLE_COLUMN_METADATA
+ Expr *pExpr
+#else
Expr *pExpr,
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
const char **pzOrigDb,
const char **pzOrigTab,
- const char **pzOrigCol,
+ const char **pzOrigCol
#endif
- u8 *pEstWidth
){
char const *zType = 0;
int j;
- u8 estWidth = 1;
#ifdef SQLITE_ENABLE_COLUMN_METADATA
char const *zOrigDb = 0;
char const *zOrigTab = 0;
@@ -119002,33 +119250,32 @@ static const char *columnTypeImpl(
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
- zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth);
+ zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol);
}
- }else if( pTab->pSchema ){
- /* A real table */
+ }else{
+ /* A real table or a CTE table */
assert( !pS );
- if( iCol<0 ) iCol = pTab->iPKey;
- assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
#ifdef SQLITE_ENABLE_COLUMN_METADATA
+ if( iCol<0 ) iCol = pTab->iPKey;
+ assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
zType = "INTEGER";
zOrigCol = "rowid";
}else{
zOrigCol = pTab->aCol[iCol].zName;
zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
- estWidth = pTab->aCol[iCol].szEst;
}
zOrigTab = pTab->zName;
- if( pNC->pParse ){
+ if( pNC->pParse && pTab->pSchema ){
int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName;
}
#else
+ assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
zType = "INTEGER";
}else{
zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
- estWidth = pTab->aCol[iCol].szEst;
}
#endif
}
@@ -119047,7 +119294,7 @@ static const char *columnTypeImpl(
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
- zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth);
+ zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
break;
}
#endif
@@ -119061,7 +119308,6 @@ static const char *columnTypeImpl(
*pzOrigCol = zOrigCol;
}
#endif
- if( pEstWidth ) *pEstWidth = estWidth;
return zType;
}
@@ -119088,7 +119334,7 @@ static void generateColumnTypes(
const char *zOrigDb = 0;
const char *zOrigTab = 0;
const char *zOrigCol = 0;
- zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0);
+ zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
/* The vdbe must make its own copy of the column-type and other
** column specific strings, in case the schema is reset before this
@@ -119098,7 +119344,7 @@ static void generateColumnTypes(
sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT);
sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT);
#else
- zType = columnType(&sNC, p, 0, 0, 0, 0);
+ zType = columnType(&sNC, p, 0, 0, 0);
#endif
sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
}
@@ -119140,9 +119386,9 @@ static Table *tableWithCursor(SrcList *pList, int iCursor){
** other words, the zSpan of the result expression.
**
** short=ON, full=OFF: (This is the default setting). If the result
-** refers directly to a table column, then the result
-** column name is just the table column name: COLUMN.
-** Otherwise use zSpan.
+** refers directly to a table column, then the
+** result column name is just the table column
+** name: COLUMN. Otherwise use zSpan.
**
** full=ON, short=ANY: If the result refers directly to a table column,
** then the result column name with the table name
@@ -119178,6 +119424,8 @@ static void generateColumnNames(
Expr *p = pEList->a[i].pExpr;
assert( p!=0 );
+ assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */
+ assert( p->op!=TK_COLUMN || p->pTab!=0 ); /* Covering idx not yet coded */
if( pEList->a[i].zName ){
/* An AS clause always takes first priority */
char *zName = pEList->a[i].zName;
@@ -119253,6 +119501,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
nCol = pEList->nExpr;
aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
testcase( aCol==0 );
+ if( nCol>32767 ) nCol = 32767;
}else{
nCol = 0;
aCol = 0;
@@ -119272,7 +119521,9 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
pColExpr = pColExpr->pRight;
assert( pColExpr!=0 );
}
- if( pColExpr->op==TK_COLUMN && pColExpr->pTab!=0 ){
+ if( (pColExpr->op==TK_COLUMN || pColExpr->op==TK_AGG_COLUMN)
+ && pColExpr->pTab!=0
+ ){
/* For columns use the column name name */
int iCol = pColExpr->iColumn;
Table *pTab = pColExpr->pTab;
@@ -119347,7 +119598,6 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
int i;
Expr *p;
struct ExprList_item *a;
- u64 szAll = 0;
assert( pSelect!=0 );
assert( (pSelect->selFlags & SF_Resolved)!=0 );
@@ -119360,10 +119610,11 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
const char *zType;
int n, m;
p = a[i].pExpr;
- zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
- szAll += pCol->szEst;
+ 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))>0 ){
+ if( zType ){
+ m = sqlite3Strlen30(zType);
n = sqlite3Strlen30(pCol->zName);
pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
if( pCol->zName ){
@@ -119377,7 +119628,7 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
}
}
- pTab->szTabRow = sqlite3LogEst(szAll*4);
+ pTab->szTabRow = 1; /* Any non-zero value works */
}
/*
@@ -119420,19 +119671,16 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
** Get a VDBE for the given parser context. Create a new one if necessary.
** If an error occurs, return NULL and leave a message in pParse.
*/
-static SQLITE_NOINLINE Vdbe *allocVdbe(Parse *pParse){
- Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
- if( v ) sqlite3VdbeAddOp2(v, OP_Init, 0, 1);
+SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
+ if( pParse->pVdbe ){
+ return pParse->pVdbe;
+ }
if( pParse->pToplevel==0
&& OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
){
pParse->okConstFactor = 1;
}
- return v;
-}
-SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
- Vdbe *v = pParse->pVdbe;
- return v ? v : allocVdbe(pParse);
+ return sqlite3VdbeCreate(pParse);
}
@@ -119705,7 +119953,7 @@ static void generateWithRecursiveQuery(
/* Output the single row in Current */
addrCont = sqlite3VdbeMakeLabel(v);
codeOffset(v, regOffset, addrCont);
- selectInnerLoop(pParse, p, p->pEList, iCurrent,
+ selectInnerLoop(pParse, p, iCurrent,
0, 0, pDest, addrCont, addrBreak);
if( regLimit ){
sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak);
@@ -119843,15 +120091,9 @@ static int multiSelect(
db = pParse->db;
pPrior = p->pPrior;
dest = *pDest;
- if( pPrior->pOrderBy ){
- sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
- selectOpName(p->op));
- rc = 1;
- goto multi_select_end;
- }
- if( pPrior->pLimit ){
- sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before",
- selectOpName(p->op));
+ 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;
}
@@ -120029,7 +120271,7 @@ static int multiSelect(
computeLimitRegisters(pParse, p, iBreak);
sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
iStart = sqlite3VdbeCurrentAddr(v);
- selectInnerLoop(pParse, p, p->pEList, unionTab,
+ selectInnerLoop(pParse, p, unionTab,
0, 0, &dest, iCont, iBreak);
sqlite3VdbeResolveLabel(v, iCont);
sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v);
@@ -120107,7 +120349,7 @@ static int multiSelect(
iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);
sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v);
sqlite3ReleaseTempReg(pParse, r1);
- selectInnerLoop(pParse, p, p->pEList, tab1,
+ selectInnerLoop(pParse, p, tab1,
0, 0, &dest, iCont, iBreak);
sqlite3VdbeResolveLabel(v, iCont);
sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v);
@@ -120767,7 +121009,9 @@ 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_FromJoin)
+ && pExpr->iRightJoinTable==pSubst->iTable
+ ){
pExpr->iRightJoinTable = pSubst->iNewTable;
}
if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){
@@ -120880,68 +121124,74 @@ static void substSelect(
** exist on the table t1, a complete scan of the data might be
** avoided.
**
-** Flattening is only attempted if all of the following are true:
+** Flattening is subject to the following constraints:
**
-** (1) The subquery and the outer query do not both use aggregates.
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** The subquery and the outer query cannot both be aggregates.
**
-** (2) The subquery is not an aggregate or (2a) the outer query is not a join
-** and (2b) the outer query does not use subqueries other than the one
-** FROM-clause subquery that is a candidate for flattening. (2b is
-** due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** (2) If the subquery is an aggregate then
+** (2a) the outer query must not be a join and
+** (2b) the outer query must not use subqueries
+** other than the one FROM-clause subquery that is a candidate
+** for flattening. (This is due to ticket [2f7170d73bf9abf80]
+** from 2015-02-09.)
**
-** (3) The subquery is not the right operand of a LEFT JOIN
-** or (a) the subquery is not itself a join and (b) the FROM clause
-** of the subquery does not contain a virtual table and (c) the
-** outer query is not an aggregate.
+** (3) If the subquery is the right operand of a LEFT JOIN then
+** (3a) the subquery may not be a join and
+** (3b) the FROM clause of the subquery may not contain a virtual
+** table and
+** (3c) the outer query may not be an aggregate.
**
-** (4) The subquery is not DISTINCT.
+** (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
** (4) has since been expanded to exclude all DISTINCT subqueries.
**
-** (6) The subquery does not use aggregates or the outer query is not
-** DISTINCT.
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** If the subquery is aggregate, the outer query may not be DISTINCT.
**
-** (7) The subquery has a FROM clause. TODO: For subqueries without
+** (7) The subquery must have a FROM clause. TODO: For subqueries without
** A FROM clause, consider adding a FROM clause with the special
** table sqlite_once that consists of a single row containing a
** single NULL.
**
-** (8) The subquery does not use LIMIT or the outer query is not a join.
+** (8) If the subquery uses LIMIT then the outer query may not be a join.
**
-** (9) The subquery does not use LIMIT or the outer query does not use
-** aggregates.
+** (9) If the subquery uses LIMIT then the outer query may not be aggregate.
**
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
** accidently carried the comment forward until 2014-09-15. Original
-** text: "The subquery does not use aggregates or the outer query
-** does not use LIMIT."
+** constraint: "If the subquery is aggregate then the outer query
+** may not use LIMIT."
**
-** (11) The subquery and the outer query do not both have ORDER BY clauses.
+** (11) The subquery and the outer query may not both have ORDER BY clauses.
**
** (**) Not implemented. Subsumed into restriction (3). Was previously
** a separate restriction deriving from ticket #350.
**
-** (13) The subquery and outer query do not both use LIMIT.
+** (13) The subquery and outer query may not both use LIMIT.
**
-** (14) The subquery does not use OFFSET.
+** (14) The subquery may not use OFFSET.
**
-** (15) The outer query is not part of a compound select or the
-** subquery does not have a LIMIT clause.
+** (15) If the outer query is part of a compound select, then the
+** subquery may not use LIMIT.
** (See ticket #2339 and ticket [02a8e81d44]).
**
-** (16) The outer query is not an aggregate or the subquery does
-** not contain ORDER BY. (Ticket #2942) This used to not matter
+** (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.
**
-** (17) The sub-query is not a compound select, or it is a UNION ALL
-** compound clause made up entirely of non-aggregate queries, and
-** the parent query:
-**
-** * is not itself part of a compound select,
-** * is not an aggregate or DISTINCT query, and
-** * is not a join
+** (17) If the subquery is a compound select, then
+** (17a) all compound operators must be a UNION ALL, and
+** (17b) no terms within the subquery compound may be aggregate
+** or DISTINCT, and
+** (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.
**
** The parent and sub-query may contain WHERE clauses. Subject to
** rules (11), (13) and (14), they may also contain ORDER BY,
@@ -120957,29 +121207,32 @@ 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
+** ORDER BY clause of the parent must be simple references to
** columns of the sub-query.
**
-** (19) The subquery does not use LIMIT or the outer query does not
+** (19) If the subquery uses LIMIT then the outer query may not
** have a WHERE clause.
**
-** (20) If the sub-query is a compound select, then it must not use
-** an ORDER BY clause. Ticket #3773. We could relax this constraint
-** somewhat by saying that the terms of the ORDER BY clause must
-** appear as unmodified result columns in the outer query. But we
-** have other optimizations in mind to deal with that case.
+** (**) Subsumed into (17d3). Was: If the sub-query is a compound select,
+** then it must not use an ORDER BY clause - Ticket #3773. Because
+** of (17d3), then only way to have a compound subquery is if it is
+** the only term in the FROM clause of the outer query. But if the
+** only term in the FROM clause has an ORDER BY, then it will be
+** implemented as a co-routine and the flattener will never be called.
**
-** (21) The subquery does not use LIMIT or the outer query is not
+** (21) If the subquery uses LIMIT then the outer query may not be
** DISTINCT. (See ticket [752e1646fc]).
**
-** (22) The subquery is not a recursive CTE.
+** (22) The subquery may not be a recursive CTE.
**
-** (23) The parent is not a recursive CTE, or the sub-query is not a
-** compound query. This restriction is because transforming the
+** (**) 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
** parent to a compound query confuses the code that handles
** recursive queries in multiSelect().
**
-** (24) The subquery is not an aggregate that uses the built-in min() or
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** 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.)
@@ -120987,7 +121240,7 @@ static void substSelect(
**
** 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
-** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
+** uses aggregates.
**
** If flattening is not attempted, this routine is a no-op and returns 0.
** If flattening is attempted this routine returns 1.
@@ -120999,8 +121252,7 @@ static int flattenSubquery(
Parse *pParse, /* Parsing context */
Select *p, /* The parent or outer SELECT statement */
int iFrom, /* Index in p->pSrc->a[] of the inner subquery */
- int isAgg, /* True if outer SELECT uses aggregate functions */
- int subqueryIsAgg /* True if the subquery uses aggregate functions */
+ int isAgg /* True if outer SELECT uses aggregate functions */
){
const char *zSavedAuthContext = pParse->zAuthContext;
Select *pParent; /* Current UNION ALL term of the other query */
@@ -121020,7 +121272,7 @@ static int flattenSubquery(
/* Check to see if flattening is permitted. Return 0 if not.
*/
assert( p!=0 );
- assert( p->pPrior==0 ); /* Unable to flatten compound queries */
+ assert( p->pPrior==0 );
if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
pSrc = p->pSrc;
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
@@ -121028,16 +121280,6 @@ static int flattenSubquery(
iParent = pSubitem->iCursor;
pSub = pSubitem->pSelect;
assert( pSub!=0 );
- if( subqueryIsAgg ){
- if( isAgg ) return 0; /* Restriction (1) */
- if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */
- if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery))
- || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0
- || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0
- ){
- return 0; /* Restriction (2b) */
- }
- }
pSubSrc = pSub->pSrc;
assert( pSubSrc );
@@ -121052,13 +121294,10 @@ static int flattenSubquery(
return 0; /* Restriction (15) */
}
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
- if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */
+ if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (4) */
if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){
return 0; /* Restrictions (8)(9) */
}
- if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){
- return 0; /* Restriction (6) */
- }
if( p->pOrderBy && pSub->pOrderBy ){
return 0; /* Restriction (11) */
}
@@ -121067,18 +121306,14 @@ static int flattenSubquery(
if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
return 0; /* Restriction (21) */
}
- testcase( pSub->selFlags & SF_Recursive );
- testcase( pSub->selFlags & SF_MinMaxAgg );
- if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){
- return 0; /* Restrictions (22) and (24) */
- }
- if( (p->selFlags & SF_Recursive) && pSub->pPrior ){
- return 0; /* Restriction (23) */
+ if( pSub->selFlags & (SF_Recursive) ){
+ return 0; /* Restrictions (22) */
}
/*
** If the subquery is the right operand of a LEFT JOIN, then the
- ** subquery may not be a join itself. Example of why this is not allowed:
+ ** subquery may not be a join itself (3a). Example of why this is not
+ ** allowed:
**
** t1 LEFT OUTER JOIN (t2 JOIN t3)
**
@@ -121089,54 +121324,53 @@ 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. 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.
+ ** 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 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){
- return 0; /* Restriction (3) */
+ /* (3a) (3c) (3b) */
+ return 0;
}
}
#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. */
+ ** 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;
}
#endif
- /* Restriction 17: If the sub-query is a compound SELECT, then it must
+ /* 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
** that make up the compound SELECT are allowed to be aggregate or distinct
** queries.
*/
if( pSub->pPrior ){
- if( pSub->pOrderBy ){
- return 0; /* Restriction 20 */
- }
if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){
- return 0;
+ return 0; /* (17d1), (17d2), or (17d3) */
}
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->pEList->nExpr==pSub1->pEList->nExpr );
- if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0
- || (pSub1->pPrior && pSub1->op!=TK_ALL)
- || pSub1->pSrc->nSrc<1
+ if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */
+ || (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */
+ || pSub1->pSrc->nSrc<1 /* (17c) */
){
return 0;
}
testcase( pSub1->pSrc->nSrc>1 );
}
- /* Restriction 18. */
+ /* Restriction (18). */
if( p->pOrderBy ){
int ii;
for(ii=0; ii<p->pOrderBy->nExpr; ii++){
@@ -121145,6 +121379,23 @@ static int flattenSubquery(
}
}
+ /* 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 );
+
+ /* Ex-restriction (20):
+ ** A compound subquery must be the only term in the FROM clause of the
+ ** outer query by restriction (17d3). But if that term also has an
+ ** ORDER BY clause, then the subquery will be implemented by co-routine
+ ** and so the flattener will never be invoked. Hence, it is not possible
+ ** for the subquery to be a compound and have an ORDER BY clause.
+ */
+ assert( pSub->pPrior==0 || pSub->pOrderBy==0 );
+
/***** If we reach this point, flattening is permitted. *****/
SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n",
pSub->zSelName, pSub, iFrom));
@@ -121365,18 +121616,7 @@ static int flattenSubquery(
if( isLeftJoin>0 ){
setJoinExpr(pWhere, iNewParent);
}
- if( subqueryIsAgg ){
- assert( pParent->pHaving==0 );
- pParent->pHaving = pParent->pWhere;
- pParent->pWhere = pWhere;
- pParent->pHaving = sqlite3ExprAnd(db,
- sqlite3ExprDup(db, pSub->pHaving, 0), pParent->pHaving
- );
- assert( pParent->pGroupBy==0 );
- pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
- }else{
- pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
- }
+ pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
if( db->mallocFailed==0 ){
SubstContext x;
x.pParse = pParse;
@@ -121439,9 +121679,13 @@ static int flattenSubquery(
**
** Do not attempt this optimization if:
**
-** (1) The inner query is an aggregate. (In that case, we'd really want
-** to copy the outer WHERE-clause terms onto the HAVING clause of the
-** inner query. But they probably won't help there so do not bother.)
+** (1) (** This restriction was removed on 2017-09-29. We used to
+** disallow this optimization for aggregate subqueries, but now
+** it is allowed by putting the extra terms on the HAVING clause.
+** The added HAVING clause is pointless if the subquery lacks
+** a GROUP BY clause. But such a HAVING clause is also harmless
+** so there does not appear to be any reason to add extra logic
+** to suppress it. **)
**
** (2) The inner query is the recursive part of a common table expression.
**
@@ -121466,16 +121710,22 @@ static int pushDownWhereTerms(
){
Expr *pNew;
int nChng = 0;
- Select *pX; /* For looping over compound SELECTs in pSubq */
if( pWhere==0 ) return 0;
- for(pX=pSubq; pX; pX=pX->pPrior){
- if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
- testcase( pX->selFlags & SF_Aggregate );
- testcase( pX->selFlags & SF_Recursive );
- testcase( pX!=pSubq );
- return 0; /* restrictions (1) and (2) */
+ if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */
+
+#ifdef SQLITE_DEBUG
+ /* Only the first term of a compound can have a WITH clause. But make
+ ** sure no other terms are marked SF_Recursive in case something changes
+ ** in the future.
+ */
+ {
+ Select *pX;
+ for(pX=pSubq; pX; pX=pX->pPrior){
+ assert( (pX->selFlags & (SF_Recursive))==0 );
}
}
+#endif
+
if( pSubq->pLimit!=0 ){
return 0; /* restriction (3) */
}
@@ -121483,7 +121733,7 @@ static int pushDownWhereTerms(
nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor);
pWhere = pWhere->pLeft;
}
- if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
+ if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction (5) */
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
nChng++;
while( pSubq ){
@@ -121495,7 +121745,11 @@ static int pushDownWhereTerms(
x.isLeftJoin = 0;
x.pEList = pSubq->pEList;
pNew = substExpr(&x, pNew);
- pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
+ if( pSubq->selFlags & SF_Aggregate ){
+ pSubq->pHaving = sqlite3ExprAnd(pParse->db, pSubq->pHaving, pNew);
+ }else{
+ pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
+ }
pSubq = pSubq->pPrior;
}
}
@@ -121823,7 +122077,8 @@ static int withExpand(
);
return SQLITE_ERROR;
}
- assert( pTab->nTabRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
+ assert( pTab->nTabRef==1 ||
+ ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
pCte->zCteErr = "circular reference: %s";
pSavedWith = pParse->pWith;
@@ -121880,7 +122135,7 @@ static int withExpand(
*/
static void selectPopWith(Walker *pWalker, Select *p){
Parse *pParse = pWalker->pParse;
- if( pParse->pWith && p->pPrior==0 ){
+ if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){
With *pWith = findRightmost(p)->pWith;
if( pWith!=0 ){
assert( pParse->pWith==pWith );
@@ -121935,7 +122190,7 @@ static int selectExpander(Walker *pWalker, Select *p){
}
pTabList = p->pSrc;
pEList = p->pEList;
- if( p->pWith ){
+ if( OK_IF_ALWAYS_TRUE(p->pWith) ){
sqlite3WithPush(pParse, p->pWith, 0);
}
@@ -121967,7 +122222,11 @@ static int selectExpander(Walker *pWalker, Select *p){
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return WRC_Abort;
pTab->nTabRef = 1;
- pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
+ if( pFrom->zAlias ){
+ pTab->zName = sqlite3DbStrDup(db, pFrom->zAlias);
+ }else{
+ pTab->zName = sqlite3MPrintf(db, "subquery_%p", (void*)pTab);
+ }
while( pSel->pPrior ){ pSel = pSel->pPrior; }
sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
pTab->iPKey = -1;
@@ -122177,12 +122436,10 @@ static int selectExpander(Walker *pWalker, Select *p){
sqlite3ExprListDelete(db, pEList);
p->pEList = pNew;
}
-#if SQLITE_MAX_COLUMN
if( p->pEList && p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many columns in result set");
return WRC_Abort;
}
-#endif
return WRC_Continue;
}
@@ -122236,7 +122493,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
Walker w;
w.xExprCallback = sqlite3ExprWalkNoop;
w.pParse = pParse;
- if( pParse->hasCompound ){
+ if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){
w.xSelectCallback = convertCompoundSelectToSubquery;
w.xSelectCallback2 = 0;
sqlite3WalkSelect(&w, pSelect);
@@ -122324,15 +122581,13 @@ SQLITE_PRIVATE void sqlite3SelectPrep(
Select *p, /* The SELECT statement being coded. */
NameContext *pOuterNC /* Name context for container */
){
- sqlite3 *db;
- if( NEVER(p==0) ) return;
- db = pParse->db;
- if( db->mallocFailed ) return;
+ assert( p!=0 || pParse->db->mallocFailed );
+ if( pParse->db->mallocFailed ) return;
if( p->selFlags & SF_HasTypeInfo ) return;
sqlite3SelectExpand(pParse, p);
- if( pParse->nErr || db->mallocFailed ) return;
+ if( pParse->nErr || pParse->db->mallocFailed ) return;
sqlite3ResolveSelectNames(pParse, p, pOuterNC);
- if( pParse->nErr || db->mallocFailed ) return;
+ if( pParse->nErr || pParse->db->mallocFailed ) return;
sqlite3SelectAddTypeInfo(pParse, p);
}
@@ -122627,24 +122882,24 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
Expr *pExpr;
Expr *pCount;
sqlite3 *db;
- if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate query */
+ if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
pExpr = p->pEList->a[0].pExpr;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */
- if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Must be count() */
+ if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
- if( p->pSrc->nSrc!=1 ) return 0; /* One table in the FROM clause */
+ if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
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 subquery */
+ if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */
do{
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
if( pSub->pWhere ) return 0; /* No WHERE clause */
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
- pSub = pSub->pPrior; /* Repeat over compound terms */
+ pSub = pSub->pPrior; /* Repeat over compound */
}while( pSub );
- /* If we reach this point, that means it is OK to perform the transformation */
+ /* If we reach this point then it is OK to perform the transformation */
db = pParse->db;
pCount = pExpr;
@@ -122776,7 +123031,6 @@ SQLITE_PRIVATE int sqlite3Select(
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
struct SrcList_item *pItem = &pTabList->a[i];
Select *pSub = pItem->pSelect;
- int isAggSub;
Table *pTab = pItem->pTab;
if( pSub==0 ) continue;
@@ -122788,13 +123042,36 @@ SQLITE_PRIVATE int sqlite3Select(
goto select_end;
}
- isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
- if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
+ /* Do not try to flatten an aggregate subquery.
+ **
+ ** Flattening an aggregate subquery is only possible if the outer query
+ ** is not a join. But if the outer query is not a join, then the subquery
+ ** will be implemented as a co-routine and there is no advantage to
+ ** flattening in that case.
+ */
+ if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
+ assert( pSub->pGroupBy==0 );
+
+ /* If the subquery contains an ORDER BY clause and if
+ ** it will be implemented as a co-routine, then do not flatten. This
+ ** restriction allows SQL constructs like this:
+ **
+ ** SELECT expensive_function(x)
+ ** FROM (SELECT x FROM tab ORDER BY y LIMIT 10);
+ **
+ ** The expensive_function() is only computed on the 10 rows that
+ ** are output, rather than every row of the table.
+ */
+ if( pSub->pOrderBy!=0
+ && i==0
+ && (pTabList->nSrc==1
+ || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0)
+ ){
+ continue;
+ }
+
+ if( flattenSubquery(pParse, p, i, isAgg) ){
/* This subquery can be absorbed into its parent. */
- if( isAggSub ){
- isAgg = 1;
- p->selFlags |= SF_Aggregate;
- }
i = -1;
}
pTabList = p->pSrc;
@@ -122833,10 +123110,14 @@ SQLITE_PRIVATE int sqlite3Select(
struct SrcList_item *pItem = &pTabList->a[i];
SelectDest dest;
Select *pSub;
+#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+ const char *zSavedAuthContext;
+#endif
- /* Issue SQLITE_READ authorizations with a fake column name for any tables that
- ** are referenced but from which no values are extracted. Examples of where these
- ** kinds of null SQLITE_READ authorizations would occur:
+ /* Issue SQLITE_READ authorizations with a fake column name for any
+ ** tables that are referenced but from which no values are extracted.
+ ** Examples of where these kinds of null SQLITE_READ authorizations
+ ** would occur:
**
** SELECT count(*) FROM t1; -- SQLITE_READ t1.""
** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2.""
@@ -122844,10 +123125,10 @@ SQLITE_PRIVATE int sqlite3Select(
** The fake column name is an empty string. It is possible for a table to
** have a column named by the empty string, in which case there is no way to
** distinguish between an unreferenced table and an actual reference to the
- ** "" column. The original design was for the fake column name to be a NULL,
+ ** "" column. The original design was for the fake column name to be a NULL,
** which would be unambiguous. But legacy authorization callbacks might
- ** assume the column name is non-NULL and segfault. The use of an empty string
- ** for the fake column name seems safer.
+ ** assume the column name is non-NULL and segfault. The use of an empty
+ ** string for the fake column name seems safer.
*/
if( pItem->colUsed==0 ){
sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
@@ -122899,16 +123180,14 @@ SQLITE_PRIVATE int sqlite3Select(
#endif
}
+ zSavedAuthContext = pParse->zAuthContext;
+ pParse->zAuthContext = pItem->zName;
+
/* Generate code to implement the subquery
**
- ** The subquery is implemented as a co-routine if all of these are true:
- ** (1) The subquery is guaranteed to be the outer loop (so that it
- ** does not need to be computed more than once)
- ** (2) The ALL keyword after SELECT is omitted. (Applications are
- ** allowed to say "SELECT ALL" instead of just "SELECT" to disable
- ** the use of co-routines.)
- ** (3) Co-routines are not disabled using sqlite3_test_control()
- ** with SQLITE_TESTCTRL_OPTIMIZATIONS.
+ ** 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?
@@ -122916,13 +123195,12 @@ SQLITE_PRIVATE int sqlite3Select(
if( i==0
&& (pTabList->nSrc==1
|| (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
- && (p->selFlags & SF_All)==0 /* (2) */
- && OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */
){
/* 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));
@@ -122980,6 +123258,7 @@ SQLITE_PRIVATE int sqlite3Select(
}
if( db->mallocFailed ) goto select_end;
pParse->nHeight -= sqlite3SelectExprHeight(p);
+ pParse->zAuthContext = zSavedAuthContext;
#endif
}
@@ -123127,7 +123406,8 @@ SQLITE_PRIVATE int sqlite3Select(
}
/* Use the standard inner loop. */
- selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
+ assert( p->pEList==pEList );
+ selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest,
sqlite3WhereContinueLabel(pWInfo),
sqlite3WhereBreakLabel(pWInfo));
@@ -123430,7 +123710,7 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
finalizeAggFunctions(pParse, &sAggInfo);
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
- selectInnerLoop(pParse, p, p->pEList, -1, &sSort,
+ selectInnerLoop(pParse, p, -1, &sSort,
&sDistinct, pDest,
addrOutputRow+1, addrSetAbort);
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
@@ -123574,7 +123854,7 @@ SQLITE_PRIVATE int sqlite3Select(
sSort.pOrderBy = 0;
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
- selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
+ selectInnerLoop(pParse, p, -1, 0, 0,
pDest, addrEnd, addrEnd);
sqlite3ExprListDelete(db, pDel);
}
@@ -124414,7 +124694,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const ch
*pp = (*pp)->pNext;
}
sqlite3DeleteTrigger(db, pTrigger);
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
}
@@ -125735,12 +126015,6 @@ static void updateVirtualTable(
if( pWInfo==0 ) return;
/* Populate the argument registers. */
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
- if( pRowid ){
- sqlite3ExprCode(pParse, pRowid, regArg+1);
- }else{
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
- }
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
@@ -125748,6 +126022,23 @@ static void updateVirtualTable(
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
}
}
+ 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{
+ 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);
+ }
bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
@@ -125932,7 +126223,8 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
int rc = SQLITE_OK; /* Return code from service routines */
Btree *pMain; /* The database being vacuumed */
Btree *pTemp; /* The temporary database we vacuum into */
- int saved_flags; /* Saved value of the db->flags */
+ u16 saved_mDbFlags; /* Saved value of db->mDbFlags */
+ u32 saved_flags; /* Saved value of db->flags */
int saved_nChange; /* Saved value of db->nChange */
int saved_nTotalChange; /* Saved value of db->nTotalChange */
u8 saved_mTrace; /* Saved trace settings */
@@ -125955,11 +126247,12 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
** restored before returning. Then set the writable-schema flag, and
** disable CHECK and foreign key constraints. */
saved_flags = db->flags;
+ saved_mDbFlags = db->mDbFlags;
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
saved_mTrace = db->mTrace;
- db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks
- | SQLITE_PreferBuiltin | SQLITE_Vacuum);
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
+ db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows);
db->mTrace = 0;
@@ -126070,8 +126363,8 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
"WHERE type='table'AND coalesce(rootpage,1)>0",
zDbMain
);
- assert( (db->flags & SQLITE_Vacuum)!=0 );
- db->flags &= ~SQLITE_Vacuum;
+ assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
+ db->mDbFlags &= ~DBFLAG_Vacuum;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Copy the triggers, views, and virtual tables from the main database
@@ -126139,6 +126432,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
end_of_vacuum:
/* Restore the original value of db->flags */
db->init.iDb = 0;
+ db->mDbFlags = saved_mDbFlags;
db->flags = saved_flags;
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
@@ -126215,8 +126509,10 @@ SQLITE_PRIVATE Module *sqlite3VtabCreateModule(
){
Module *pMod;
int nName = sqlite3Strlen30(zName);
- pMod = (Module *)sqlite3DbMallocRawNN(db, sizeof(Module) + nName + 1);
- if( pMod ){
+ pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1);
+ if( pMod==0 ){
+ sqlite3OomFault(db);
+ }else{
Module *pDel;
char *zCopy = (char *)(&pMod[1]);
memcpy(zCopy, zName, nName+1);
@@ -126691,13 +126987,14 @@ static int vtabCallConstructor(
}
}
- zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
+ zModuleName = sqlite3DbStrDup(db, pTab->zName);
if( !zModuleName ){
return SQLITE_NOMEM_BKPT;
}
- pVTable = sqlite3DbMallocZero(db, sizeof(VTable));
+ pVTable = sqlite3MallocZero(sizeof(VTable));
if( !pVTable ){
+ sqlite3OomFault(db);
sqlite3DbFree(db, zModuleName);
return SQLITE_NOMEM_BKPT;
}
@@ -126817,6 +127114,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "%s", zErr);
+ pParse->rc = rc;
}
sqlite3DbFree(db, zErr);
}
@@ -126906,10 +127204,10 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
*/
SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
VtabCtx *pCtx;
- Parse *pParse;
int rc = SQLITE_OK;
Table *pTab;
char *zErr = 0;
+ Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
@@ -126926,55 +127224,55 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
pTab = pCtx->pTab;
assert( IsVirtual(pTab) );
- pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
- if( pParse==0 ){
- rc = SQLITE_NOMEM_BKPT;
- }else{
- pParse->declareVtab = 1;
- pParse->db = db;
- pParse->nQueryLoop = 1;
-
- if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr)
- && pParse->pNewTable
- && !db->mallocFailed
- && !pParse->pNewTable->pSelect
- && !IsVirtual(pParse->pNewTable)
- ){
- if( !pTab->aCol ){
- Table *pNew = pParse->pNewTable;
- Index *pIdx;
- pTab->aCol = pNew->aCol;
- pTab->nCol = pNew->nCol;
- pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
- pNew->nCol = 0;
- pNew->aCol = 0;
- assert( pTab->pIndex==0 );
- if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){
- rc = SQLITE_ERROR;
- }
- pIdx = pNew->pIndex;
- if( pIdx ){
- assert( pIdx->pNext==0 );
- pTab->pIndex = pIdx;
- pNew->pIndex = 0;
- pIdx->pTable = pTab;
- }
+ memset(&sParse, 0, sizeof(sParse));
+ sParse.declareVtab = 1;
+ sParse.db = db;
+ sParse.nQueryLoop = 1;
+ if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
+ && sParse.pNewTable
+ && !db->mallocFailed
+ && !sParse.pNewTable->pSelect
+ && !IsVirtual(sParse.pNewTable)
+ ){
+ if( !pTab->aCol ){
+ Table *pNew = sParse.pNewTable;
+ Index *pIdx;
+ pTab->aCol = pNew->aCol;
+ pTab->nCol = pNew->nCol;
+ pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
+ pNew->nCol = 0;
+ pNew->aCol = 0;
+ assert( pTab->pIndex==0 );
+ assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 );
+ if( !HasRowid(pNew)
+ && pCtx->pVTable->pMod->pModule->xUpdate!=0
+ && sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1
+ ){
+ /* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0)
+ ** or else must have a single-column PRIMARY KEY */
+ rc = SQLITE_ERROR;
+ }
+ pIdx = pNew->pIndex;
+ if( pIdx ){
+ assert( pIdx->pNext==0 );
+ pTab->pIndex = pIdx;
+ pNew->pIndex = 0;
+ pIdx->pTable = pTab;
}
- pCtx->bDeclared = 1;
- }else{
- sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
- sqlite3DbFree(db, zErr);
- rc = SQLITE_ERROR;
}
- pParse->declareVtab = 0;
+ pCtx->bDeclared = 1;
+ }else{
+ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
+ sqlite3DbFree(db, zErr);
+ rc = SQLITE_ERROR;
+ }
+ sParse.declareVtab = 0;
- if( pParse->pVdbe ){
- sqlite3VdbeFinalize(pParse->pVdbe);
- }
- sqlite3DeleteTable(db, pParse->pNewTable);
- sqlite3ParserReset(pParse);
- sqlite3StackFree(db, pParse);
+ if( sParse.pVdbe ){
+ sqlite3VdbeFinalize(sParse.pVdbe);
}
+ sqlite3DeleteTable(db, sParse.pNewTable);
+ sqlite3ParserReset(&sParse);
assert( (rc&0xff)==rc );
rc = sqlite3ApiExit(db, rc);
@@ -127952,7 +128250,6 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
** WO_LE == SQLITE_INDEX_CONSTRAINT_LE
** WO_GT == SQLITE_INDEX_CONSTRAINT_GT
** WO_GE == SQLITE_INDEX_CONSTRAINT_GE
-** WO_MATCH == SQLITE_INDEX_CONSTRAINT_MATCH
*/
#define WO_IN 0x0001
#define WO_EQ 0x0002
@@ -127960,7 +128257,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
#define WO_LE (WO_EQ<<(TK_LE-TK_EQ))
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
-#define WO_MATCH 0x0040
+#define WO_AUX 0x0040 /* Op useful to virtual tables only */
#define WO_IS 0x0080
#define WO_ISNULL 0x0100
#define WO_OR 0x0200 /* Two or more OR-connected terms */
@@ -128773,7 +129070,7 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
pWalker->eCode = 1;
}else if( pExpr->op==TK_FUNCTION ){
int d1;
- char d2[3];
+ char d2[4];
if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){
pWalker->eCode = 1;
}
@@ -128996,7 +129293,7 @@ static void codeDeferredSeek(
*/
static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
assert( nReg>0 );
- if( sqlite3ExprIsVector(p) ){
+ if( p && sqlite3ExprIsVector(p) ){
#ifndef SQLITE_OMIT_SUBQUERY
if( (p->flags & EP_xIsSelect) ){
Vdbe *v = pParse->pVdbe;
@@ -129049,9 +129346,9 @@ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
}
/*
-** 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.
+** 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.
*/
static void whereIndexExprTrans(
Index *pIdx, /* The Index */
@@ -130328,12 +130625,12 @@ static int isLikeOrGlob(
int *pisComplete, /* True if the only wildcard is % in the last character */
int *pnoCase /* True if uppercase is equivalent to lowercase */
){
- const char *z = 0; /* String on RHS of LIKE operator */
+ const u8 *z = 0; /* String on RHS of LIKE operator */
Expr *pRight, *pLeft; /* Right and left size of LIKE operator */
ExprList *pList; /* List of operands to the LIKE operator */
int c; /* One character in z[] */
int cnt; /* Number of non-wildcard prefix characters */
- char wc[3]; /* Wildcard characters */
+ char wc[4]; /* Wildcard characters */
sqlite3 *db = pParse->db; /* Database connection */
sqlite3_value *pVal = 0;
int op; /* Opcode of pRight */
@@ -130355,12 +130652,12 @@ static int isLikeOrGlob(
int iCol = pRight->iColumn;
pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB);
if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
- z = (char *)sqlite3_value_text(pVal);
+ z = sqlite3_value_text(pVal);
}
sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
}else if( op==TK_STRING ){
- z = pRight->u.zToken;
+ z = (u8*)pRight->u.zToken;
}
if( z ){
@@ -130380,16 +130677,42 @@ static int isLikeOrGlob(
return 0;
}
}
+
+ /* Count the number of prefix characters prior to the first wildcard */
cnt = 0;
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
cnt++;
+ if( c==wc[3] && z[cnt]!=0 ) cnt++;
}
+
+ /* The optimization is possible only if (1) the pattern does not begin
+ ** with a wildcard and if (2) the non-wildcard prefix does not end with
+ ** an (illegal 0xff) character. The second condition is necessary so
+ ** that we can increment the prefix key to find an upper bound for the
+ ** range search.
+ */
if( cnt!=0 && 255!=(u8)z[cnt-1] ){
Expr *pPrefix;
+
+ /* A "complete" match if the pattern ends with "*" or "%" */
*pisComplete = c==wc[0] && z[cnt+1]==0;
- pPrefix = sqlite3Expr(db, TK_STRING, z);
- if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
+
+ /* Get the pattern prefix. Remove all escapes from the prefix. */
+ pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
+ if( pPrefix ){
+ int iFrom, iTo;
+ char *zNew = pPrefix->u.zToken;
+ zNew[cnt] = 0;
+ for(iFrom=iTo=0; iFrom<cnt; iFrom++){
+ if( zNew[iFrom]==wc[3] ) iFrom++;
+ zNew[iTo++] = zNew[iFrom];
+ }
+ zNew[iTo] = 0;
+ }
*ppPrefix = pPrefix;
+
+ /* If the RHS pattern is a bound parameter, make arrangements to
+ ** reprepare the statement when that parameter is rebound */
if( op==TK_VARIABLE ){
Vdbe *v = pParse->pVdbe;
sqlite3VdbeSetVarmask(v, pRight->iColumn);
@@ -130420,48 +130743,84 @@ static int isLikeOrGlob(
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
-** Check to see if the given expression is of the form
-**
-** column OP expr
-**
-** where OP is one of MATCH, GLOB, LIKE or REGEXP and "column" is a
-** column of a virtual table.
-**
-** If it is then return TRUE. If not, return FALSE.
-*/
-static int isMatchOfColumn(
+** Check to see if the pExpr expression is a form that needs to be passed
+** to the xBestIndex method of virtual tables. Forms of interest include:
+**
+** Expression Virtual Table Operator
+** ----------------------- ---------------------------------
+** 1. column MATCH expr SQLITE_INDEX_CONSTRAINT_MATCH
+** 2. column GLOB expr SQLITE_INDEX_CONSTRAINT_GLOB
+** 3. column LIKE expr SQLITE_INDEX_CONSTRAINT_LIKE
+** 4. column REGEXP expr SQLITE_INDEX_CONSTRAINT_REGEXP
+** 5. column != expr SQLITE_INDEX_CONSTRAINT_NE
+** 6. expr != column SQLITE_INDEX_CONSTRAINT_NE
+** 7. column IS NOT expr SQLITE_INDEX_CONSTRAINT_ISNOT
+** 8. expr IS NOT column SQLITE_INDEX_CONSTRAINT_ISNOT
+** 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
+** "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
+** is a match. The usual return is 1, but if the RHS is also a column
+** of virtual table in forms (5) or (7) then return 2.
+**
+** If the expression matches none of the patterns above, return 0.
+*/
+static int isAuxiliaryVtabOperator(
Expr *pExpr, /* Test this expression */
- unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */
-){
- static const struct Op2 {
- const char *zOp;
- unsigned char eOp2;
- } aOp[] = {
- { "match", SQLITE_INDEX_CONSTRAINT_MATCH },
- { "glob", SQLITE_INDEX_CONSTRAINT_GLOB },
- { "like", SQLITE_INDEX_CONSTRAINT_LIKE },
- { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP }
- };
- ExprList *pList;
- Expr *pCol; /* Column reference */
- int i;
+ unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */
+ Expr **ppLeft, /* Column expression to left of MATCH/op2 */
+ Expr **ppRight /* Expression to left of MATCH/op2 */
+){
+ if( pExpr->op==TK_FUNCTION ){
+ static const struct Op2 {
+ const char *zOp;
+ unsigned char eOp2;
+ } aOp[] = {
+ { "match", SQLITE_INDEX_CONSTRAINT_MATCH },
+ { "glob", SQLITE_INDEX_CONSTRAINT_GLOB },
+ { "like", SQLITE_INDEX_CONSTRAINT_LIKE },
+ { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP }
+ };
+ ExprList *pList;
+ Expr *pCol; /* Column reference */
+ int i;
- if( pExpr->op!=TK_FUNCTION ){
- return 0;
- }
- pList = pExpr->x.pList;
- if( pList==0 || pList->nExpr!=2 ){
- return 0;
- }
- pCol = pList->a[1].pExpr;
- if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){
- return 0;
- }
- for(i=0; i<ArraySize(aOp); i++){
- if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
- *peOp2 = aOp[i].eOp2;
- return 1;
+ pList = pExpr->x.pList;
+ if( pList==0 || pList->nExpr!=2 ){
+ return 0;
+ }
+ pCol = pList->a[1].pExpr;
+ if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){
+ return 0;
+ }
+ for(i=0; i<ArraySize(aOp); i++){
+ if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
+ *peOp2 = aOp[i].eOp2;
+ *ppRight = pList->a[0].pExpr;
+ *ppLeft = pCol;
+ return 1;
+ }
+ }
+ }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
+ int res = 0;
+ Expr *pLeft = pExpr->pLeft;
+ Expr *pRight = pExpr->pRight;
+ if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->pTab) ){
+ res++;
+ }
+ if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->pTab) ){
+ res++;
+ SWAP(Expr*, pLeft, pRight);
}
+ *ppLeft = pLeft;
+ *ppRight = pRight;
+ if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE;
+ if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT;
+ if( pExpr->op==TK_NOTNULL ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOTNULL;
+ return res;
}
return 0;
}
@@ -130712,7 +131071,7 @@ static void exprAnalyzeOrTerm(
for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
assert( pAndTerm->pExpr );
if( allowedOp(pAndTerm->pExpr->op)
- || pAndTerm->eOperator==WO_MATCH
+ || pAndTerm->eOperator==WO_AUX
){
b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor);
}
@@ -130914,7 +131273,6 @@ static void exprAnalyzeOrTerm(
static int termIsEquivalence(Parse *pParse, Expr *pExpr){
char aff1, aff2;
CollSeq *pColl;
- const char *zColl1, *zColl2;
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;
@@ -130927,11 +131285,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
}
pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
- pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
- zColl1 = pColl ? pColl->zName : 0;
- pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
- zColl2 = pColl ? pColl->zName : 0;
- return sqlite3_stricmp(zColl1, zColl2)==0;
+ return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
}
/*
@@ -131294,41 +131648,46 @@ static void exprAnalyze(
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
#ifndef SQLITE_OMIT_VIRTUALTABLE
- /* Add a WO_MATCH auxiliary term to the constraint set if the
- ** current expression is of the form: column MATCH expr.
+ /* 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 && isMatchOfColumn(pExpr, &eOp2) ){
- int idxNew;
+ if( pWC->op==TK_AND ){
Expr *pRight, *pLeft;
- WhereTerm *pNewTerm;
- Bitmask prereqColumn, prereqExpr;
-
- pRight = pExpr->x.pList->a[0].pExpr;
- pLeft = pExpr->x.pList->a[1].pExpr;
- 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);
+ int res = isAuxiliaryVtabOperator(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);
+ }
+ 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;
}
- 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_MATCH;
- 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 */
@@ -132007,8 +132366,8 @@ static int findIndexCol(
&& p->iColumn==pIdx->aiColumn[iCol]
&& p->iTable==iBase
){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
- if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){
+ CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr);
+ if( 0==sqlite3StrICmp(pColl->zName, zColl) ){
return i;
}
}
@@ -132472,7 +132831,7 @@ static sqlite3_index_info *allocateIndexInfo(
testcase( pTerm->eOperator & WO_ISNULL );
testcase( pTerm->eOperator & WO_IS );
testcase( pTerm->eOperator & WO_ALL );
- if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
+ if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
assert( pTerm->u.leftColumn>=(-1) );
nTerm++;
@@ -132520,7 +132879,7 @@ static sqlite3_index_info *allocateIndexInfo(
pUsage;
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
- u8 op;
+ u16 op;
if( pTerm->leftCursor != pSrc->iCursor ) continue;
if( pTerm->prereqRight & mUnusable ) continue;
assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
@@ -132528,34 +132887,40 @@ static sqlite3_index_info *allocateIndexInfo(
testcase( pTerm->eOperator & WO_IS );
testcase( pTerm->eOperator & WO_ISNULL );
testcase( pTerm->eOperator & WO_ALL );
- if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
+ if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
assert( pTerm->u.leftColumn>=(-1) );
pIdxCons[j].iColumn = pTerm->u.leftColumn;
pIdxCons[j].iTermOffset = i;
- op = (u8)pTerm->eOperator & WO_ALL;
+ op = pTerm->eOperator & WO_ALL;
if( op==WO_IN ) op = WO_EQ;
- if( op==WO_MATCH ){
- op = pTerm->eMatchOp;
- }
- pIdxCons[j].op = op;
- /* The direct assignment in the previous line is possible only because
- ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
- ** following asserts verify this fact. */
- assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
- assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
- assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
- assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
- assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
- assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
- assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
-
- if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
- && sqlite3ExprIsVector(pTerm->pExpr->pRight)
- ){
- if( i<16 ) mNoOmit |= (1 << i);
- if( op==WO_LT ) pIdxCons[j].op = WO_LE;
- if( op==WO_GT ) pIdxCons[j].op = WO_GE;
+ if( op==WO_AUX ){
+ pIdxCons[j].op = pTerm->eMatchOp;
+ }else if( op & (WO_ISNULL|WO_IS) ){
+ if( op==WO_ISNULL ){
+ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL;
+ }else{
+ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS;
+ }
+ }else{
+ pIdxCons[j].op = (u8)op;
+ /* The direct assignment in the previous line is possible only because
+ ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
+ ** following asserts verify this fact. */
+ assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
+ assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
+ assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
+ assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
+ assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
+ 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)
+ ){
+ if( i<16 ) mNoOmit |= (1 << i);
+ if( op==WO_LT ) pIdxCons[j].op = WO_LE;
+ if( op==WO_GT ) pIdxCons[j].op = WO_GE;
+ }
}
j++;
@@ -133483,18 +133848,19 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
** Return TRUE if all of the following are true:
**
** (1) X has the same or lower cost that Y
-** (2) X is a proper subset of Y
-** (3) X skips at least as many columns as Y
-**
-** By "proper subset" we mean that X uses fewer WHERE clause terms
-** than Y and that every WHERE clause term used by X is also used
-** by 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
+** (5) If X is a covering index, than Y is too
**
+** 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
-** relationship is inverted and needs to be adjusted. The third rule
+** 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.
+** deserve a lower cost even if it is a proper subset of Y. Constraint (5)
+** was added because a covering index probably deserves to have a lower cost
+** than a non-covering index even if it is a proper subset.
*/
static int whereLoopCheaperProperSubset(
const WhereLoop *pX, /* First WhereLoop to compare */
@@ -133516,6 +133882,10 @@ 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
+ && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
+ return 0; /* Constraint (5) */
+ }
return 1; /* All conditions meet */
}
@@ -134267,7 +134637,7 @@ static int indexMightHelpWithOrderBy(
}else if( (aColExpr = pIndex->aColExpr)!=0 ){
for(jj=0; jj<pIndex->nKeyCol; jj++){
if( pIndex->aiColumn[jj]!=XN_EXPR ) continue;
- if( sqlite3ExprCompare(0, pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
+ if( sqlite3ExprCompareSkip(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
return 1;
}
}
@@ -135177,14 +135547,10 @@ static i8 wherePathSatisfiesOrderBy(
if( j>=pLoop->nLTerm ) continue;
}
if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){
- const char *z1, *z2;
- pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- z1 = pColl->zName;
- pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- z2 = pColl->zName;
- if( sqlite3StrICmp(z1, z2)!=0 ) continue;
+ if( sqlite3ExprCollSeqMatch(pWInfo->pParse,
+ pOrderBy->a[i].pExpr, pTerm->pExpr)==0 ){
+ continue;
+ }
testcase( pTerm->pExpr->op==TK_IS );
}
obSat |= MASKBIT(i);
@@ -135256,7 +135622,7 @@ static i8 wherePathSatisfiesOrderBy(
if( pIndex ){
iColumn = pIndex->aiColumn[j];
revIdx = pIndex->aSortOrder[j];
- if( iColumn==pIndex->pTable->iPKey ) iColumn = -1;
+ if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID;
}else{
iColumn = XN_ROWID;
revIdx = 0;
@@ -135283,19 +135649,18 @@ static i8 wherePathSatisfiesOrderBy(
testcase( wctrlFlags & WHERE_GROUPBY );
testcase( wctrlFlags & WHERE_DISTINCTBY );
if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
- if( iColumn>=(-1) ){
+ if( iColumn>=XN_ROWID ){
if( pOBExpr->op!=TK_COLUMN ) continue;
if( pOBExpr->iTable!=iCur ) continue;
if( pOBExpr->iColumn!=iColumn ) continue;
}else{
- if( sqlite3ExprCompare(0,
- pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){
+ Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr;
+ if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){
continue;
}
}
- if( iColumn>=0 ){
- pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
- if( !pColl ) pColl = db->pDfltColl;
+ if( iColumn!=XN_ROWID ){
+ pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
}
pLoop->u.btree.nIdxCol = j+1;
@@ -135932,6 +136297,7 @@ static int exprIsDeterministic(Expr *p){
memset(&w, 0, sizeof(w));
w.eCode = 1;
w.xExprCallback = exprNodeIsDeterministic;
+ w.xSelectCallback = sqlite3SelectWalkFail;
sqlite3WalkExpr(&w, p);
return w.eCode;
}
@@ -136141,36 +136507,37 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( wctrlFlags & WHERE_WANT_DISTINCT ){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
- }
-
- /* Assign a bit from the bitmask to every term in the FROM clause.
- **
- ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
- **
- ** The rule of the previous sentence ensures thta if X is the bitmask for
- ** a table T, then X-1 is the bitmask for all other tables to the left of T.
- ** Knowing the bitmask for all tables to the left of a left join is
- ** important. Ticket #3015.
- **
- ** Note that bitmasks are created for all pTabList->nSrc tables in
- ** pTabList, not just the first nTabList tables. nTabList is normally
- ** equal to pTabList->nSrc but might be shortened to 1 if the
- ** WHERE_OR_SUBCLAUSE flag is set.
- */
- for(ii=0; ii<pTabList->nSrc; ii++){
- createMask(pMaskSet, pTabList->a[ii].iCursor);
- sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
- }
-#ifdef SQLITE_DEBUG
- {
- Bitmask mx = 0;
- for(ii=0; ii<pTabList->nSrc; ii++){
- Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
- assert( m>=mx );
- mx = m;
+ }else{
+ /* Assign a bit from the bitmask to every term in the FROM clause.
+ **
+ ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
+ **
+ ** The rule of the previous sentence ensures thta if X is the bitmask for
+ ** a table T, then X-1 is the bitmask for all other tables to the left of T.
+ ** Knowing the bitmask for all tables to the left of a left join is
+ ** important. Ticket #3015.
+ **
+ ** Note that bitmasks are created for all pTabList->nSrc tables in
+ ** pTabList, not just the first nTabList tables. nTabList is normally
+ ** equal to pTabList->nSrc but might be shortened to 1 if the
+ ** WHERE_OR_SUBCLAUSE flag is set.
+ */
+ ii = 0;
+ do{
+ createMask(pMaskSet, pTabList->a[ii].iCursor);
+ sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
+ }while( (++ii)<pTabList->nSrc );
+ #ifdef SQLITE_DEBUG
+ {
+ Bitmask mx = 0;
+ for(ii=0; ii<pTabList->nSrc; ii++){
+ Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
+ assert( m>=mx );
+ mx = m;
+ }
}
+ #endif
}
-#endif
/* Analyze all of the subexpressions. */
sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
@@ -136394,7 +136761,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
Index *pIx = pLoop->u.btree.pIndex;
int iIndexCur;
int op = OP_OpenRead;
- /* iAuxArg is always set if to a positive value if ONEPASS is possible */
+ /* iAuxArg is always set to a positive value if ONEPASS is possible */
assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 );
if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx)
&& (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0
@@ -136975,7 +137342,8 @@ static void disableLookaside(Parse *pParse){
** YY_MAX_SHIFT Maximum value for shift actions
** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
-** YY_MIN_REDUCE Maximum value for reduce actions
+** YY_MIN_REDUCE Minimum value for reduce actions
+** YY_MAX_REDUCE Maximum value for reduce actions
** YY_ERROR_ACTION The yy_action[] code for syntax error
** YY_ACCEPT_ACTION The yy_action[] code for accept
** YY_NO_ACTION The yy_action[] code for no-op
@@ -136987,7 +137355,7 @@ static void disableLookaside(Parse *pParse){
#define YYCODETYPE unsigned char
#define YYNOCODE 252
#define YYACTIONTYPE unsigned short int
-#define YYWILDCARD 69
+#define YYWILDCARD 83
#define sqlite3ParserTOKENTYPE Token
typedef union {
int yyinit;
@@ -137094,415 +137462,415 @@ typedef union {
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (1565)
+#define YY_ACTTAB_COUNT (1566)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 324, 410, 342, 747, 747, 203, 939, 353, 969, 98,
- /* 10 */ 98, 98, 98, 91, 96, 96, 96, 96, 95, 95,
- /* 20 */ 94, 94, 94, 93, 350, 1323, 155, 155, 2, 808,
- /* 30 */ 971, 971, 98, 98, 98, 98, 20, 96, 96, 96,
- /* 40 */ 96, 95, 95, 94, 94, 94, 93, 350, 92, 89,
- /* 50 */ 178, 99, 100, 90, 847, 850, 839, 839, 97, 97,
- /* 60 */ 98, 98, 98, 98, 350, 96, 96, 96, 96, 95,
- /* 70 */ 95, 94, 94, 94, 93, 350, 324, 339, 969, 262,
- /* 80 */ 364, 251, 212, 169, 287, 404, 282, 403, 199, 786,
- /* 90 */ 242, 411, 21, 950, 378, 280, 93, 350, 787, 95,
- /* 100 */ 95, 94, 94, 94, 93, 350, 971, 971, 96, 96,
- /* 110 */ 96, 96, 95, 95, 94, 94, 94, 93, 350, 808,
- /* 120 */ 328, 242, 411, 1235, 826, 1235, 132, 99, 100, 90,
- /* 130 */ 847, 850, 839, 839, 97, 97, 98, 98, 98, 98,
- /* 140 */ 449, 96, 96, 96, 96, 95, 95, 94, 94, 94,
- /* 150 */ 93, 350, 324, 819, 348, 347, 120, 818, 120, 75,
- /* 160 */ 52, 52, 950, 951, 952, 1084, 977, 146, 360, 262,
- /* 170 */ 369, 261, 950, 975, 954, 976, 92, 89, 178, 370,
- /* 180 */ 230, 370, 971, 971, 1141, 360, 359, 101, 818, 818,
- /* 190 */ 820, 383, 24, 1286, 380, 427, 412, 368, 978, 379,
- /* 200 */ 978, 1032, 324, 99, 100, 90, 847, 850, 839, 839,
- /* 210 */ 97, 97, 98, 98, 98, 98, 372, 96, 96, 96,
- /* 220 */ 96, 95, 95, 94, 94, 94, 93, 350, 950, 132,
- /* 230 */ 890, 449, 971, 971, 890, 60, 94, 94, 94, 93,
- /* 240 */ 350, 950, 951, 952, 954, 103, 360, 950, 384, 333,
- /* 250 */ 697, 52, 52, 99, 100, 90, 847, 850, 839, 839,
- /* 260 */ 97, 97, 98, 98, 98, 98, 1022, 96, 96, 96,
- /* 270 */ 96, 95, 95, 94, 94, 94, 93, 350, 324, 454,
- /* 280 */ 995, 449, 227, 61, 157, 243, 343, 114, 1025, 1211,
- /* 290 */ 147, 826, 950, 372, 1071, 950, 319, 950, 951, 952,
- /* 300 */ 194, 10, 10, 401, 398, 397, 1211, 1213, 971, 971,
- /* 310 */ 757, 171, 170, 157, 396, 336, 950, 951, 952, 697,
- /* 320 */ 819, 310, 153, 950, 818, 320, 82, 23, 80, 99,
- /* 330 */ 100, 90, 847, 850, 839, 839, 97, 97, 98, 98,
- /* 340 */ 98, 98, 888, 96, 96, 96, 96, 95, 95, 94,
- /* 350 */ 94, 94, 93, 350, 324, 818, 818, 820, 277, 231,
- /* 360 */ 300, 950, 951, 952, 950, 951, 952, 1211, 194, 25,
- /* 370 */ 449, 401, 398, 397, 950, 354, 300, 449, 950, 74,
- /* 380 */ 449, 1, 396, 132, 971, 971, 950, 224, 224, 808,
- /* 390 */ 10, 10, 950, 951, 952, 1290, 132, 52, 52, 414,
- /* 400 */ 52, 52, 1063, 1063, 338, 99, 100, 90, 847, 850,
- /* 410 */ 839, 839, 97, 97, 98, 98, 98, 98, 1114, 96,
- /* 420 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 350,
- /* 430 */ 324, 1113, 427, 417, 701, 427, 426, 1260, 1260, 262,
- /* 440 */ 369, 261, 950, 950, 951, 952, 752, 950, 951, 952,
- /* 450 */ 449, 751, 449, 1058, 1037, 950, 951, 952, 442, 706,
- /* 460 */ 971, 971, 1058, 393, 92, 89, 178, 446, 446, 446,
- /* 470 */ 51, 51, 52, 52, 438, 773, 1024, 92, 89, 178,
- /* 480 */ 172, 99, 100, 90, 847, 850, 839, 839, 97, 97,
- /* 490 */ 98, 98, 98, 98, 198, 96, 96, 96, 96, 95,
- /* 500 */ 95, 94, 94, 94, 93, 350, 324, 427, 407, 909,
- /* 510 */ 694, 950, 951, 952, 92, 89, 178, 224, 224, 157,
- /* 520 */ 241, 221, 418, 299, 771, 910, 415, 374, 449, 414,
- /* 530 */ 58, 323, 1061, 1061, 1242, 378, 971, 971, 378, 772,
- /* 540 */ 448, 911, 362, 735, 296, 681, 9, 9, 52, 52,
- /* 550 */ 234, 329, 234, 256, 416, 736, 280, 99, 100, 90,
- /* 560 */ 847, 850, 839, 839, 97, 97, 98, 98, 98, 98,
- /* 570 */ 449, 96, 96, 96, 96, 95, 95, 94, 94, 94,
- /* 580 */ 93, 350, 324, 422, 72, 449, 827, 120, 367, 449,
- /* 590 */ 10, 10, 5, 301, 203, 449, 177, 969, 253, 419,
- /* 600 */ 255, 771, 200, 175, 233, 10, 10, 836, 836, 36,
- /* 610 */ 36, 1289, 971, 971, 724, 37, 37, 348, 347, 424,
- /* 620 */ 203, 260, 771, 969, 232, 930, 1316, 870, 337, 1316,
- /* 630 */ 421, 848, 851, 99, 100, 90, 847, 850, 839, 839,
- /* 640 */ 97, 97, 98, 98, 98, 98, 268, 96, 96, 96,
- /* 650 */ 96, 95, 95, 94, 94, 94, 93, 350, 324, 840,
- /* 660 */ 449, 978, 813, 978, 1200, 449, 909, 969, 715, 349,
- /* 670 */ 349, 349, 928, 177, 449, 930, 1317, 254, 198, 1317,
- /* 680 */ 12, 12, 910, 402, 449, 27, 27, 250, 971, 971,
- /* 690 */ 118, 716, 162, 969, 38, 38, 268, 176, 911, 771,
- /* 700 */ 432, 1265, 939, 353, 39, 39, 316, 991, 324, 99,
- /* 710 */ 100, 90, 847, 850, 839, 839, 97, 97, 98, 98,
- /* 720 */ 98, 98, 928, 96, 96, 96, 96, 95, 95, 94,
- /* 730 */ 94, 94, 93, 350, 449, 329, 449, 357, 971, 971,
- /* 740 */ 1041, 316, 929, 340, 893, 893, 386, 669, 670, 671,
- /* 750 */ 275, 1318, 317, 992, 40, 40, 41, 41, 268, 99,
- /* 760 */ 100, 90, 847, 850, 839, 839, 97, 97, 98, 98,
- /* 770 */ 98, 98, 449, 96, 96, 96, 96, 95, 95, 94,
- /* 780 */ 94, 94, 93, 350, 324, 449, 355, 449, 992, 449,
- /* 790 */ 1016, 330, 42, 42, 786, 270, 449, 273, 449, 228,
- /* 800 */ 449, 298, 449, 787, 449, 28, 28, 29, 29, 31,
- /* 810 */ 31, 449, 1141, 449, 971, 971, 43, 43, 44, 44,
- /* 820 */ 45, 45, 11, 11, 46, 46, 887, 78, 887, 268,
- /* 830 */ 268, 105, 105, 47, 47, 99, 100, 90, 847, 850,
- /* 840 */ 839, 839, 97, 97, 98, 98, 98, 98, 449, 96,
- /* 850 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 350,
- /* 860 */ 324, 449, 117, 449, 1073, 158, 449, 691, 48, 48,
- /* 870 */ 229, 1241, 449, 1250, 449, 414, 449, 334, 449, 245,
- /* 880 */ 449, 33, 33, 49, 49, 449, 50, 50, 246, 1141,
- /* 890 */ 971, 971, 34, 34, 122, 122, 123, 123, 124, 124,
- /* 900 */ 56, 56, 268, 81, 249, 35, 35, 197, 196, 195,
- /* 910 */ 324, 99, 100, 90, 847, 850, 839, 839, 97, 97,
- /* 920 */ 98, 98, 98, 98, 449, 96, 96, 96, 96, 95,
- /* 930 */ 95, 94, 94, 94, 93, 350, 449, 691, 449, 1141,
- /* 940 */ 971, 971, 968, 1207, 106, 106, 268, 1209, 268, 1266,
- /* 950 */ 2, 886, 268, 886, 335, 1040, 53, 53, 107, 107,
- /* 960 */ 324, 99, 100, 90, 847, 850, 839, 839, 97, 97,
- /* 970 */ 98, 98, 98, 98, 449, 96, 96, 96, 96, 95,
- /* 980 */ 95, 94, 94, 94, 93, 350, 449, 1070, 449, 1066,
- /* 990 */ 971, 971, 1039, 267, 108, 108, 445, 330, 331, 133,
- /* 1000 */ 223, 175, 301, 225, 385, 1255, 104, 104, 121, 121,
- /* 1010 */ 324, 99, 88, 90, 847, 850, 839, 839, 97, 97,
- /* 1020 */ 98, 98, 98, 98, 1141, 96, 96, 96, 96, 95,
- /* 1030 */ 95, 94, 94, 94, 93, 350, 449, 346, 449, 167,
- /* 1040 */ 971, 971, 925, 810, 371, 318, 202, 202, 373, 263,
- /* 1050 */ 394, 202, 74, 208, 721, 722, 119, 119, 112, 112,
- /* 1060 */ 324, 406, 100, 90, 847, 850, 839, 839, 97, 97,
- /* 1070 */ 98, 98, 98, 98, 449, 96, 96, 96, 96, 95,
- /* 1080 */ 95, 94, 94, 94, 93, 350, 449, 752, 449, 344,
- /* 1090 */ 971, 971, 751, 278, 111, 111, 74, 714, 713, 704,
- /* 1100 */ 286, 877, 749, 1279, 257, 77, 109, 109, 110, 110,
- /* 1110 */ 1230, 285, 1134, 90, 847, 850, 839, 839, 97, 97,
- /* 1120 */ 98, 98, 98, 98, 1233, 96, 96, 96, 96, 95,
- /* 1130 */ 95, 94, 94, 94, 93, 350, 86, 444, 449, 3,
- /* 1140 */ 1193, 449, 1069, 132, 351, 120, 1013, 86, 444, 780,
- /* 1150 */ 3, 1091, 202, 376, 447, 351, 1229, 120, 55, 55,
- /* 1160 */ 449, 57, 57, 822, 873, 447, 449, 208, 449, 704,
- /* 1170 */ 449, 877, 237, 433, 435, 120, 439, 428, 361, 120,
- /* 1180 */ 54, 54, 132, 449, 433, 826, 52, 52, 26, 26,
- /* 1190 */ 30, 30, 381, 132, 408, 443, 826, 689, 264, 389,
- /* 1200 */ 116, 269, 272, 32, 32, 83, 84, 120, 274, 120,
- /* 1210 */ 120, 276, 85, 351, 451, 450, 83, 84, 818, 1054,
- /* 1220 */ 1038, 427, 429, 85, 351, 451, 450, 120, 120, 818,
- /* 1230 */ 377, 218, 281, 822, 1107, 1140, 86, 444, 409, 3,
- /* 1240 */ 1087, 1098, 430, 431, 351, 302, 303, 1146, 1021, 818,
- /* 1250 */ 818, 820, 821, 19, 447, 1015, 1004, 1003, 1005, 1273,
- /* 1260 */ 818, 818, 820, 821, 19, 289, 159, 291, 293, 7,
- /* 1270 */ 315, 173, 259, 433, 1129, 363, 252, 1232, 375, 1037,
- /* 1280 */ 295, 434, 168, 986, 399, 826, 284, 1204, 1203, 205,
- /* 1290 */ 1276, 308, 1249, 86, 444, 983, 3, 1247, 332, 144,
- /* 1300 */ 130, 351, 72, 135, 59, 83, 84, 756, 137, 365,
- /* 1310 */ 1126, 447, 85, 351, 451, 450, 139, 226, 818, 140,
- /* 1320 */ 156, 62, 314, 314, 313, 215, 311, 366, 392, 678,
- /* 1330 */ 433, 185, 141, 1234, 142, 160, 148, 1136, 1198, 382,
- /* 1340 */ 189, 67, 826, 180, 388, 248, 1218, 1099, 219, 818,
- /* 1350 */ 818, 820, 821, 19, 247, 190, 266, 154, 390, 271,
- /* 1360 */ 191, 192, 83, 84, 1006, 405, 1057, 182, 321, 85,
- /* 1370 */ 351, 451, 450, 1056, 183, 818, 341, 132, 181, 706,
- /* 1380 */ 1055, 420, 76, 444, 1029, 3, 322, 1028, 283, 1048,
- /* 1390 */ 351, 1095, 1027, 1288, 1047, 71, 204, 6, 288, 290,
- /* 1400 */ 447, 1096, 1094, 1093, 79, 292, 818, 818, 820, 821,
- /* 1410 */ 19, 294, 297, 437, 345, 441, 102, 1184, 1077, 433,
- /* 1420 */ 238, 425, 73, 305, 239, 304, 325, 240, 423, 306,
- /* 1430 */ 307, 826, 213, 1012, 22, 945, 452, 214, 216, 217,
- /* 1440 */ 453, 1001, 115, 996, 125, 126, 235, 127, 665, 352,
- /* 1450 */ 326, 83, 84, 358, 166, 244, 179, 327, 85, 351,
- /* 1460 */ 451, 450, 134, 356, 818, 113, 885, 806, 883, 136,
- /* 1470 */ 128, 138, 738, 258, 184, 899, 143, 145, 63, 64,
- /* 1480 */ 65, 66, 129, 902, 187, 186, 898, 8, 13, 188,
- /* 1490 */ 265, 891, 149, 202, 980, 818, 818, 820, 821, 19,
- /* 1500 */ 150, 387, 161, 680, 285, 391, 151, 395, 400, 193,
- /* 1510 */ 68, 14, 236, 279, 15, 69, 717, 825, 131, 824,
- /* 1520 */ 853, 70, 746, 16, 413, 750, 4, 174, 220, 222,
- /* 1530 */ 152, 779, 857, 774, 201, 77, 74, 868, 17, 854,
- /* 1540 */ 852, 908, 18, 907, 207, 206, 934, 163, 436, 210,
- /* 1550 */ 935, 164, 209, 165, 440, 856, 823, 690, 87, 211,
- /* 1560 */ 309, 312, 1281, 940, 1280,
+ /* 0 */ 324, 1323, 155, 155, 2, 203, 94, 94, 94, 93,
+ /* 10 */ 350, 98, 98, 98, 98, 91, 95, 95, 94, 94,
+ /* 20 */ 94, 93, 350, 268, 99, 100, 90, 971, 971, 847,
+ /* 30 */ 850, 839, 839, 97, 97, 98, 98, 98, 98, 350,
+ /* 40 */ 969, 96, 96, 96, 96, 95, 95, 94, 94, 94,
+ /* 50 */ 93, 350, 950, 96, 96, 96, 96, 95, 95, 94,
+ /* 60 */ 94, 94, 93, 350, 250, 96, 96, 96, 96, 95,
+ /* 70 */ 95, 94, 94, 94, 93, 350, 224, 224, 969, 132,
+ /* 80 */ 888, 348, 347, 415, 172, 324, 1286, 449, 414, 950,
+ /* 90 */ 951, 952, 808, 977, 1032, 950, 300, 786, 428, 132,
+ /* 100 */ 975, 362, 976, 9, 9, 787, 132, 52, 52, 99,
+ /* 110 */ 100, 90, 971, 971, 847, 850, 839, 839, 97, 97,
+ /* 120 */ 98, 98, 98, 98, 372, 978, 241, 978, 262, 369,
+ /* 130 */ 261, 120, 950, 951, 952, 194, 58, 324, 401, 398,
+ /* 140 */ 397, 808, 427, 429, 75, 808, 1260, 1260, 132, 396,
+ /* 150 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
+ /* 160 */ 350, 99, 100, 90, 971, 971, 847, 850, 839, 839,
+ /* 170 */ 97, 97, 98, 98, 98, 98, 786, 262, 369, 261,
+ /* 180 */ 826, 262, 364, 251, 787, 1084, 101, 1114, 72, 324,
+ /* 190 */ 227, 1113, 242, 411, 442, 819, 92, 89, 178, 818,
+ /* 200 */ 1022, 268, 96, 96, 96, 96, 95, 95, 94, 94,
+ /* 210 */ 94, 93, 350, 99, 100, 90, 971, 971, 847, 850,
+ /* 220 */ 839, 839, 97, 97, 98, 98, 98, 98, 449, 372,
+ /* 230 */ 818, 818, 820, 92, 89, 178, 60, 92, 89, 178,
+ /* 240 */ 1025, 324, 357, 930, 1316, 300, 61, 1316, 52, 52,
+ /* 250 */ 836, 836, 848, 851, 96, 96, 96, 96, 95, 95,
+ /* 260 */ 94, 94, 94, 93, 350, 99, 100, 90, 971, 971,
+ /* 270 */ 847, 850, 839, 839, 97, 97, 98, 98, 98, 98,
+ /* 280 */ 92, 89, 178, 427, 412, 198, 930, 1317, 454, 995,
+ /* 290 */ 1317, 355, 1024, 324, 243, 231, 114, 277, 348, 347,
+ /* 300 */ 1242, 950, 416, 1071, 928, 840, 96, 96, 96, 96,
+ /* 310 */ 95, 95, 94, 94, 94, 93, 350, 99, 100, 90,
+ /* 320 */ 971, 971, 847, 850, 839, 839, 97, 97, 98, 98,
+ /* 330 */ 98, 98, 449, 328, 449, 120, 23, 256, 950, 951,
+ /* 340 */ 952, 968, 978, 438, 978, 324, 329, 928, 954, 701,
+ /* 350 */ 200, 175, 52, 52, 52, 52, 939, 353, 96, 96,
+ /* 360 */ 96, 96, 95, 95, 94, 94, 94, 93, 350, 99,
+ /* 370 */ 100, 90, 971, 971, 847, 850, 839, 839, 97, 97,
+ /* 380 */ 98, 98, 98, 98, 354, 449, 954, 427, 417, 427,
+ /* 390 */ 426, 1290, 92, 89, 178, 268, 253, 324, 255, 1058,
+ /* 400 */ 1037, 694, 93, 350, 383, 52, 52, 380, 1058, 374,
+ /* 410 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
+ /* 420 */ 350, 99, 100, 90, 971, 971, 847, 850, 839, 839,
+ /* 430 */ 97, 97, 98, 98, 98, 98, 228, 449, 167, 449,
+ /* 440 */ 427, 407, 157, 446, 446, 446, 349, 349, 349, 324,
+ /* 450 */ 310, 316, 991, 827, 320, 242, 411, 51, 51, 36,
+ /* 460 */ 36, 254, 96, 96, 96, 96, 95, 95, 94, 94,
+ /* 470 */ 94, 93, 350, 99, 100, 90, 971, 971, 847, 850,
+ /* 480 */ 839, 839, 97, 97, 98, 98, 98, 98, 194, 316,
+ /* 490 */ 929, 401, 398, 397, 224, 224, 1265, 939, 353, 1318,
+ /* 500 */ 317, 324, 396, 1063, 1063, 813, 414, 1061, 1061, 950,
+ /* 510 */ 299, 448, 992, 268, 96, 96, 96, 96, 95, 95,
+ /* 520 */ 94, 94, 94, 93, 350, 99, 100, 90, 971, 971,
+ /* 530 */ 847, 850, 839, 839, 97, 97, 98, 98, 98, 98,
+ /* 540 */ 757, 1041, 449, 893, 893, 386, 950, 951, 952, 410,
+ /* 550 */ 992, 747, 747, 324, 229, 268, 221, 296, 268, 771,
+ /* 560 */ 890, 378, 52, 52, 890, 421, 96, 96, 96, 96,
+ /* 570 */ 95, 95, 94, 94, 94, 93, 350, 99, 100, 90,
+ /* 580 */ 971, 971, 847, 850, 839, 839, 97, 97, 98, 98,
+ /* 590 */ 98, 98, 103, 449, 275, 384, 1241, 343, 157, 1207,
+ /* 600 */ 909, 669, 670, 671, 176, 197, 196, 195, 324, 298,
+ /* 610 */ 319, 1266, 2, 37, 37, 910, 1134, 1040, 96, 96,
+ /* 620 */ 96, 96, 95, 95, 94, 94, 94, 93, 350, 697,
+ /* 630 */ 911, 177, 99, 100, 90, 971, 971, 847, 850, 839,
+ /* 640 */ 839, 97, 97, 98, 98, 98, 98, 230, 146, 120,
+ /* 650 */ 735, 1235, 826, 270, 1141, 273, 1141, 771, 171, 170,
+ /* 660 */ 736, 1141, 82, 324, 80, 268, 697, 819, 158, 268,
+ /* 670 */ 378, 818, 78, 96, 96, 96, 96, 95, 95, 94,
+ /* 680 */ 94, 94, 93, 350, 120, 950, 393, 99, 100, 90,
+ /* 690 */ 971, 971, 847, 850, 839, 839, 97, 97, 98, 98,
+ /* 700 */ 98, 98, 818, 818, 820, 1141, 1070, 370, 331, 133,
+ /* 710 */ 1066, 1141, 1250, 198, 268, 324, 1016, 330, 245, 333,
+ /* 720 */ 24, 334, 950, 951, 952, 368, 335, 81, 96, 96,
+ /* 730 */ 96, 96, 95, 95, 94, 94, 94, 93, 350, 99,
+ /* 740 */ 100, 90, 971, 971, 847, 850, 839, 839, 97, 97,
+ /* 750 */ 98, 98, 98, 98, 132, 267, 260, 445, 330, 223,
+ /* 760 */ 175, 1289, 925, 752, 724, 318, 1073, 324, 751, 246,
+ /* 770 */ 385, 301, 301, 378, 329, 361, 344, 414, 1233, 280,
+ /* 780 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
+ /* 790 */ 350, 99, 88, 90, 971, 971, 847, 850, 839, 839,
+ /* 800 */ 97, 97, 98, 98, 98, 98, 337, 346, 721, 722,
+ /* 810 */ 449, 120, 118, 887, 162, 887, 810, 371, 324, 202,
+ /* 820 */ 202, 373, 249, 263, 202, 394, 74, 704, 208, 1069,
+ /* 830 */ 12, 12, 96, 96, 96, 96, 95, 95, 94, 94,
+ /* 840 */ 94, 93, 350, 100, 90, 971, 971, 847, 850, 839,
+ /* 850 */ 839, 97, 97, 98, 98, 98, 98, 449, 771, 232,
+ /* 860 */ 449, 278, 120, 286, 74, 704, 714, 713, 324, 342,
+ /* 870 */ 749, 877, 1209, 77, 285, 1255, 780, 52, 52, 202,
+ /* 880 */ 27, 27, 418, 96, 96, 96, 96, 95, 95, 94,
+ /* 890 */ 94, 94, 93, 350, 90, 971, 971, 847, 850, 839,
+ /* 900 */ 839, 97, 97, 98, 98, 98, 98, 86, 444, 877,
+ /* 910 */ 3, 1193, 422, 1013, 873, 435, 886, 208, 886, 689,
+ /* 920 */ 1091, 257, 116, 822, 447, 1230, 117, 1229, 86, 444,
+ /* 930 */ 177, 3, 381, 96, 96, 96, 96, 95, 95, 94,
+ /* 940 */ 94, 94, 93, 350, 339, 447, 120, 351, 120, 212,
+ /* 950 */ 169, 287, 404, 282, 403, 199, 771, 950, 433, 419,
+ /* 960 */ 439, 822, 280, 691, 1039, 264, 269, 132, 351, 153,
+ /* 970 */ 826, 376, 74, 272, 274, 276, 83, 84, 1054, 433,
+ /* 980 */ 147, 1038, 443, 85, 351, 451, 450, 281, 132, 818,
+ /* 990 */ 25, 826, 449, 120, 950, 951, 952, 83, 84, 86,
+ /* 1000 */ 444, 691, 3, 408, 85, 351, 451, 450, 449, 5,
+ /* 1010 */ 818, 203, 32, 32, 1107, 120, 447, 950, 225, 1140,
+ /* 1020 */ 818, 818, 820, 821, 19, 203, 226, 950, 38, 38,
+ /* 1030 */ 1087, 314, 314, 313, 215, 311, 120, 449, 678, 351,
+ /* 1040 */ 237, 818, 818, 820, 821, 19, 969, 409, 377, 1,
+ /* 1050 */ 433, 180, 706, 248, 950, 951, 952, 10, 10, 449,
+ /* 1060 */ 969, 247, 826, 1098, 950, 951, 952, 430, 83, 84,
+ /* 1070 */ 756, 336, 950, 20, 431, 85, 351, 451, 450, 10,
+ /* 1080 */ 10, 818, 86, 444, 969, 3, 950, 449, 302, 303,
+ /* 1090 */ 182, 950, 1146, 338, 1021, 1015, 1004, 183, 969, 447,
+ /* 1100 */ 132, 181, 76, 444, 21, 3, 449, 10, 10, 950,
+ /* 1110 */ 951, 952, 818, 818, 820, 821, 19, 715, 1279, 447,
+ /* 1120 */ 389, 233, 351, 950, 951, 952, 10, 10, 950, 951,
+ /* 1130 */ 952, 1003, 218, 433, 1005, 325, 1273, 773, 289, 291,
+ /* 1140 */ 424, 293, 351, 7, 159, 826, 363, 402, 315, 360,
+ /* 1150 */ 1129, 83, 84, 433, 1232, 716, 772, 259, 85, 351,
+ /* 1160 */ 451, 450, 358, 375, 818, 826, 360, 359, 399, 1211,
+ /* 1170 */ 157, 83, 84, 681, 98, 98, 98, 98, 85, 351,
+ /* 1180 */ 451, 450, 323, 252, 818, 295, 1211, 1213, 1235, 173,
+ /* 1190 */ 1037, 284, 434, 340, 1204, 818, 818, 820, 821, 19,
+ /* 1200 */ 308, 234, 449, 234, 96, 96, 96, 96, 95, 95,
+ /* 1210 */ 94, 94, 94, 93, 350, 818, 818, 820, 821, 19,
+ /* 1220 */ 909, 120, 39, 39, 1203, 449, 168, 360, 449, 1276,
+ /* 1230 */ 367, 449, 135, 449, 986, 910, 449, 1249, 449, 1247,
+ /* 1240 */ 449, 205, 983, 449, 370, 40, 40, 1211, 41, 41,
+ /* 1250 */ 911, 42, 42, 28, 28, 870, 29, 29, 31, 31,
+ /* 1260 */ 43, 43, 379, 44, 44, 449, 59, 449, 332, 449,
+ /* 1270 */ 432, 62, 144, 156, 449, 130, 449, 72, 449, 137,
+ /* 1280 */ 449, 365, 449, 392, 139, 45, 45, 11, 11, 46,
+ /* 1290 */ 46, 140, 1200, 449, 105, 105, 47, 47, 48, 48,
+ /* 1300 */ 33, 33, 49, 49, 1126, 449, 141, 366, 449, 185,
+ /* 1310 */ 142, 449, 1234, 50, 50, 449, 160, 449, 148, 449,
+ /* 1320 */ 1136, 382, 449, 67, 449, 34, 34, 449, 122, 122,
+ /* 1330 */ 449, 123, 123, 449, 1198, 124, 124, 56, 56, 35,
+ /* 1340 */ 35, 449, 106, 106, 53, 53, 449, 107, 107, 449,
+ /* 1350 */ 108, 108, 449, 104, 104, 449, 406, 449, 388, 449,
+ /* 1360 */ 189, 121, 121, 449, 190, 449, 119, 119, 449, 112,
+ /* 1370 */ 112, 449, 111, 111, 1218, 109, 109, 110, 110, 55,
+ /* 1380 */ 55, 266, 752, 57, 57, 54, 54, 751, 26, 26,
+ /* 1390 */ 1099, 30, 30, 219, 154, 390, 271, 191, 321, 1006,
+ /* 1400 */ 192, 405, 1057, 1056, 1055, 341, 1048, 706, 1047, 1029,
+ /* 1410 */ 322, 420, 1028, 71, 1095, 283, 288, 1027, 1288, 204,
+ /* 1420 */ 6, 297, 79, 1184, 437, 1096, 1094, 290, 345, 292,
+ /* 1430 */ 441, 1093, 294, 102, 425, 73, 423, 213, 1012, 22,
+ /* 1440 */ 452, 945, 214, 1077, 216, 217, 238, 453, 306, 304,
+ /* 1450 */ 307, 239, 240, 1001, 305, 125, 996, 126, 115, 235,
+ /* 1460 */ 127, 665, 352, 166, 244, 179, 356, 113, 885, 883,
+ /* 1470 */ 806, 136, 128, 738, 326, 138, 327, 258, 184, 899,
+ /* 1480 */ 143, 129, 145, 63, 64, 65, 66, 902, 186, 187,
+ /* 1490 */ 898, 8, 13, 188, 134, 265, 891, 202, 980, 387,
+ /* 1500 */ 150, 149, 680, 161, 391, 193, 285, 279, 395, 151,
+ /* 1510 */ 68, 717, 14, 15, 400, 69, 16, 131, 236, 825,
+ /* 1520 */ 824, 853, 746, 750, 4, 70, 174, 413, 220, 222,
+ /* 1530 */ 152, 779, 774, 77, 868, 74, 854, 201, 17, 852,
+ /* 1540 */ 908, 206, 907, 207, 18, 857, 934, 163, 436, 210,
+ /* 1550 */ 935, 164, 209, 165, 440, 856, 823, 312, 690, 87,
+ /* 1560 */ 211, 309, 1281, 940, 995, 1280,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 19, 115, 19, 117, 118, 24, 1, 2, 27, 79,
- /* 10 */ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
- /* 20 */ 90, 91, 92, 93, 94, 144, 145, 146, 147, 58,
- /* 30 */ 49, 50, 79, 80, 81, 82, 22, 84, 85, 86,
- /* 40 */ 87, 88, 89, 90, 91, 92, 93, 94, 221, 222,
- /* 50 */ 223, 70, 71, 72, 73, 74, 75, 76, 77, 78,
- /* 60 */ 79, 80, 81, 82, 94, 84, 85, 86, 87, 88,
- /* 70 */ 89, 90, 91, 92, 93, 94, 19, 94, 97, 108,
- /* 80 */ 109, 110, 99, 100, 101, 102, 103, 104, 105, 32,
- /* 90 */ 119, 120, 78, 27, 152, 112, 93, 94, 41, 88,
- /* 100 */ 89, 90, 91, 92, 93, 94, 49, 50, 84, 85,
- /* 110 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 58,
- /* 120 */ 157, 119, 120, 163, 68, 163, 65, 70, 71, 72,
- /* 130 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
- /* 140 */ 152, 84, 85, 86, 87, 88, 89, 90, 91, 92,
- /* 150 */ 93, 94, 19, 97, 88, 89, 196, 101, 196, 26,
- /* 160 */ 172, 173, 96, 97, 98, 210, 100, 22, 152, 108,
- /* 170 */ 109, 110, 27, 107, 27, 109, 221, 222, 223, 219,
- /* 180 */ 238, 219, 49, 50, 152, 169, 170, 54, 132, 133,
- /* 190 */ 134, 228, 232, 171, 231, 207, 208, 237, 132, 237,
- /* 200 */ 134, 179, 19, 70, 71, 72, 73, 74, 75, 76,
- /* 210 */ 77, 78, 79, 80, 81, 82, 152, 84, 85, 86,
- /* 220 */ 87, 88, 89, 90, 91, 92, 93, 94, 27, 65,
- /* 230 */ 30, 152, 49, 50, 34, 52, 90, 91, 92, 93,
- /* 240 */ 94, 96, 97, 98, 97, 22, 230, 27, 48, 217,
- /* 250 */ 27, 172, 173, 70, 71, 72, 73, 74, 75, 76,
- /* 260 */ 77, 78, 79, 80, 81, 82, 172, 84, 85, 86,
- /* 270 */ 87, 88, 89, 90, 91, 92, 93, 94, 19, 148,
- /* 280 */ 149, 152, 218, 24, 152, 154, 207, 156, 172, 152,
- /* 290 */ 22, 68, 27, 152, 163, 27, 164, 96, 97, 98,
- /* 300 */ 99, 172, 173, 102, 103, 104, 169, 170, 49, 50,
- /* 310 */ 90, 88, 89, 152, 113, 186, 96, 97, 98, 96,
- /* 320 */ 97, 160, 57, 27, 101, 164, 137, 196, 139, 70,
- /* 330 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- /* 340 */ 81, 82, 11, 84, 85, 86, 87, 88, 89, 90,
- /* 350 */ 91, 92, 93, 94, 19, 132, 133, 134, 23, 218,
- /* 360 */ 152, 96, 97, 98, 96, 97, 98, 230, 99, 22,
- /* 370 */ 152, 102, 103, 104, 27, 244, 152, 152, 27, 26,
- /* 380 */ 152, 22, 113, 65, 49, 50, 27, 194, 195, 58,
- /* 390 */ 172, 173, 96, 97, 98, 185, 65, 172, 173, 206,
- /* 400 */ 172, 173, 190, 191, 186, 70, 71, 72, 73, 74,
- /* 410 */ 75, 76, 77, 78, 79, 80, 81, 82, 175, 84,
- /* 420 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
- /* 430 */ 19, 175, 207, 208, 23, 207, 208, 119, 120, 108,
- /* 440 */ 109, 110, 27, 96, 97, 98, 116, 96, 97, 98,
- /* 450 */ 152, 121, 152, 179, 180, 96, 97, 98, 250, 106,
- /* 460 */ 49, 50, 188, 19, 221, 222, 223, 168, 169, 170,
- /* 470 */ 172, 173, 172, 173, 250, 124, 172, 221, 222, 223,
- /* 480 */ 26, 70, 71, 72, 73, 74, 75, 76, 77, 78,
- /* 490 */ 79, 80, 81, 82, 50, 84, 85, 86, 87, 88,
- /* 500 */ 89, 90, 91, 92, 93, 94, 19, 207, 208, 12,
- /* 510 */ 23, 96, 97, 98, 221, 222, 223, 194, 195, 152,
- /* 520 */ 199, 23, 19, 225, 26, 28, 152, 152, 152, 206,
- /* 530 */ 209, 164, 190, 191, 241, 152, 49, 50, 152, 124,
- /* 540 */ 152, 44, 219, 46, 152, 21, 172, 173, 172, 173,
- /* 550 */ 183, 107, 185, 16, 163, 58, 112, 70, 71, 72,
- /* 560 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
- /* 570 */ 152, 84, 85, 86, 87, 88, 89, 90, 91, 92,
- /* 580 */ 93, 94, 19, 207, 130, 152, 23, 196, 64, 152,
- /* 590 */ 172, 173, 22, 152, 24, 152, 98, 27, 61, 96,
- /* 600 */ 63, 26, 211, 212, 186, 172, 173, 49, 50, 172,
- /* 610 */ 173, 23, 49, 50, 26, 172, 173, 88, 89, 186,
- /* 620 */ 24, 238, 124, 27, 238, 22, 23, 103, 187, 26,
- /* 630 */ 152, 73, 74, 70, 71, 72, 73, 74, 75, 76,
- /* 640 */ 77, 78, 79, 80, 81, 82, 152, 84, 85, 86,
- /* 650 */ 87, 88, 89, 90, 91, 92, 93, 94, 19, 101,
- /* 660 */ 152, 132, 23, 134, 140, 152, 12, 97, 36, 168,
- /* 670 */ 169, 170, 69, 98, 152, 22, 23, 140, 50, 26,
- /* 680 */ 172, 173, 28, 51, 152, 172, 173, 193, 49, 50,
- /* 690 */ 22, 59, 24, 97, 172, 173, 152, 152, 44, 124,
- /* 700 */ 46, 0, 1, 2, 172, 173, 22, 23, 19, 70,
- /* 710 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- /* 720 */ 81, 82, 69, 84, 85, 86, 87, 88, 89, 90,
- /* 730 */ 91, 92, 93, 94, 152, 107, 152, 193, 49, 50,
- /* 740 */ 181, 22, 23, 111, 108, 109, 110, 7, 8, 9,
- /* 750 */ 16, 247, 248, 69, 172, 173, 172, 173, 152, 70,
- /* 760 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- /* 770 */ 81, 82, 152, 84, 85, 86, 87, 88, 89, 90,
- /* 780 */ 91, 92, 93, 94, 19, 152, 242, 152, 69, 152,
- /* 790 */ 166, 167, 172, 173, 32, 61, 152, 63, 152, 193,
- /* 800 */ 152, 152, 152, 41, 152, 172, 173, 172, 173, 172,
- /* 810 */ 173, 152, 152, 152, 49, 50, 172, 173, 172, 173,
- /* 820 */ 172, 173, 172, 173, 172, 173, 132, 138, 134, 152,
- /* 830 */ 152, 172, 173, 172, 173, 70, 71, 72, 73, 74,
- /* 840 */ 75, 76, 77, 78, 79, 80, 81, 82, 152, 84,
- /* 850 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
- /* 860 */ 19, 152, 22, 152, 195, 24, 152, 27, 172, 173,
- /* 870 */ 193, 193, 152, 152, 152, 206, 152, 217, 152, 152,
- /* 880 */ 152, 172, 173, 172, 173, 152, 172, 173, 152, 152,
- /* 890 */ 49, 50, 172, 173, 172, 173, 172, 173, 172, 173,
- /* 900 */ 172, 173, 152, 138, 152, 172, 173, 108, 109, 110,
- /* 910 */ 19, 70, 71, 72, 73, 74, 75, 76, 77, 78,
- /* 920 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88,
- /* 930 */ 89, 90, 91, 92, 93, 94, 152, 97, 152, 152,
- /* 940 */ 49, 50, 26, 193, 172, 173, 152, 152, 152, 146,
- /* 950 */ 147, 132, 152, 134, 217, 181, 172, 173, 172, 173,
- /* 960 */ 19, 70, 71, 72, 73, 74, 75, 76, 77, 78,
- /* 970 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88,
- /* 980 */ 89, 90, 91, 92, 93, 94, 152, 193, 152, 193,
- /* 990 */ 49, 50, 181, 193, 172, 173, 166, 167, 245, 246,
- /* 1000 */ 211, 212, 152, 22, 217, 152, 172, 173, 172, 173,
- /* 1010 */ 19, 70, 71, 72, 73, 74, 75, 76, 77, 78,
- /* 1020 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88,
- /* 1030 */ 89, 90, 91, 92, 93, 94, 152, 187, 152, 123,
- /* 1040 */ 49, 50, 23, 23, 23, 26, 26, 26, 23, 23,
- /* 1050 */ 23, 26, 26, 26, 7, 8, 172, 173, 172, 173,
- /* 1060 */ 19, 90, 71, 72, 73, 74, 75, 76, 77, 78,
- /* 1070 */ 79, 80, 81, 82, 152, 84, 85, 86, 87, 88,
- /* 1080 */ 89, 90, 91, 92, 93, 94, 152, 116, 152, 217,
- /* 1090 */ 49, 50, 121, 23, 172, 173, 26, 100, 101, 27,
- /* 1100 */ 101, 27, 23, 122, 152, 26, 172, 173, 172, 173,
- /* 1110 */ 152, 112, 163, 72, 73, 74, 75, 76, 77, 78,
- /* 1120 */ 79, 80, 81, 82, 163, 84, 85, 86, 87, 88,
- /* 1130 */ 89, 90, 91, 92, 93, 94, 19, 20, 152, 22,
- /* 1140 */ 23, 152, 163, 65, 27, 196, 163, 19, 20, 23,
- /* 1150 */ 22, 213, 26, 19, 37, 27, 152, 196, 172, 173,
- /* 1160 */ 152, 172, 173, 27, 23, 37, 152, 26, 152, 97,
- /* 1170 */ 152, 97, 210, 56, 163, 196, 163, 163, 100, 196,
- /* 1180 */ 172, 173, 65, 152, 56, 68, 172, 173, 172, 173,
- /* 1190 */ 172, 173, 152, 65, 163, 163, 68, 23, 152, 234,
- /* 1200 */ 26, 152, 152, 172, 173, 88, 89, 196, 152, 196,
- /* 1210 */ 196, 152, 95, 96, 97, 98, 88, 89, 101, 152,
- /* 1220 */ 152, 207, 208, 95, 96, 97, 98, 196, 196, 101,
- /* 1230 */ 96, 233, 152, 97, 152, 152, 19, 20, 207, 22,
- /* 1240 */ 152, 152, 152, 191, 27, 152, 152, 152, 152, 132,
- /* 1250 */ 133, 134, 135, 136, 37, 152, 152, 152, 152, 152,
- /* 1260 */ 132, 133, 134, 135, 136, 210, 197, 210, 210, 198,
- /* 1270 */ 150, 184, 239, 56, 201, 214, 214, 201, 239, 180,
- /* 1280 */ 214, 227, 198, 38, 176, 68, 175, 175, 175, 122,
- /* 1290 */ 155, 200, 159, 19, 20, 40, 22, 159, 159, 22,
- /* 1300 */ 70, 27, 130, 243, 240, 88, 89, 90, 189, 18,
- /* 1310 */ 201, 37, 95, 96, 97, 98, 192, 5, 101, 192,
- /* 1320 */ 220, 240, 10, 11, 12, 13, 14, 159, 18, 17,
- /* 1330 */ 56, 158, 192, 201, 192, 220, 189, 189, 201, 159,
- /* 1340 */ 158, 137, 68, 31, 45, 33, 236, 159, 159, 132,
- /* 1350 */ 133, 134, 135, 136, 42, 158, 235, 22, 177, 159,
- /* 1360 */ 158, 158, 88, 89, 159, 107, 174, 55, 177, 95,
- /* 1370 */ 96, 97, 98, 174, 62, 101, 47, 65, 66, 106,
- /* 1380 */ 174, 125, 19, 20, 174, 22, 177, 176, 174, 182,
- /* 1390 */ 27, 216, 174, 174, 182, 107, 159, 22, 215, 215,
- /* 1400 */ 37, 216, 216, 216, 137, 215, 132, 133, 134, 135,
- /* 1410 */ 136, 215, 159, 177, 94, 177, 129, 224, 205, 56,
- /* 1420 */ 226, 126, 128, 203, 229, 204, 114, 229, 127, 202,
- /* 1430 */ 201, 68, 25, 162, 26, 13, 161, 153, 153, 6,
- /* 1440 */ 151, 151, 178, 151, 165, 165, 178, 165, 4, 3,
- /* 1450 */ 249, 88, 89, 141, 22, 142, 15, 249, 95, 96,
- /* 1460 */ 97, 98, 246, 67, 101, 16, 23, 120, 23, 131,
- /* 1470 */ 111, 123, 20, 16, 125, 1, 123, 131, 78, 78,
- /* 1480 */ 78, 78, 111, 96, 122, 35, 1, 5, 22, 107,
- /* 1490 */ 140, 53, 53, 26, 60, 132, 133, 134, 135, 136,
- /* 1500 */ 107, 43, 24, 20, 112, 19, 22, 52, 52, 105,
- /* 1510 */ 22, 22, 52, 23, 22, 22, 29, 23, 39, 23,
- /* 1520 */ 23, 26, 116, 22, 26, 23, 22, 122, 23, 23,
- /* 1530 */ 22, 96, 11, 124, 35, 26, 26, 23, 35, 23,
- /* 1540 */ 23, 23, 35, 23, 22, 26, 23, 22, 24, 122,
- /* 1550 */ 23, 22, 26, 22, 24, 23, 23, 23, 22, 122,
- /* 1560 */ 23, 15, 122, 1, 122,
+ /* 0 */ 19, 144, 145, 146, 147, 24, 90, 91, 92, 93,
+ /* 10 */ 94, 54, 55, 56, 57, 58, 88, 89, 90, 91,
+ /* 20 */ 92, 93, 94, 152, 43, 44, 45, 46, 47, 48,
+ /* 30 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 94,
+ /* 40 */ 59, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+ /* 50 */ 93, 94, 59, 84, 85, 86, 87, 88, 89, 90,
+ /* 60 */ 91, 92, 93, 94, 193, 84, 85, 86, 87, 88,
+ /* 70 */ 89, 90, 91, 92, 93, 94, 194, 195, 97, 79,
+ /* 80 */ 11, 88, 89, 152, 26, 19, 171, 152, 206, 96,
+ /* 90 */ 97, 98, 72, 100, 179, 59, 152, 31, 163, 79,
+ /* 100 */ 107, 219, 109, 172, 173, 39, 79, 172, 173, 43,
+ /* 110 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ /* 120 */ 54, 55, 56, 57, 152, 132, 199, 134, 108, 109,
+ /* 130 */ 110, 196, 96, 97, 98, 99, 209, 19, 102, 103,
+ /* 140 */ 104, 72, 207, 208, 26, 72, 119, 120, 79, 113,
+ /* 150 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
+ /* 160 */ 94, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ /* 170 */ 52, 53, 54, 55, 56, 57, 31, 108, 109, 110,
+ /* 180 */ 82, 108, 109, 110, 39, 210, 68, 175, 130, 19,
+ /* 190 */ 218, 175, 119, 120, 250, 97, 221, 222, 223, 101,
+ /* 200 */ 172, 152, 84, 85, 86, 87, 88, 89, 90, 91,
+ /* 210 */ 92, 93, 94, 43, 44, 45, 46, 47, 48, 49,
+ /* 220 */ 50, 51, 52, 53, 54, 55, 56, 57, 152, 152,
+ /* 230 */ 132, 133, 134, 221, 222, 223, 66, 221, 222, 223,
+ /* 240 */ 172, 19, 193, 22, 23, 152, 24, 26, 172, 173,
+ /* 250 */ 46, 47, 48, 49, 84, 85, 86, 87, 88, 89,
+ /* 260 */ 90, 91, 92, 93, 94, 43, 44, 45, 46, 47,
+ /* 270 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ /* 280 */ 221, 222, 223, 207, 208, 46, 22, 23, 148, 149,
+ /* 290 */ 26, 242, 172, 19, 154, 218, 156, 23, 88, 89,
+ /* 300 */ 241, 59, 163, 163, 83, 101, 84, 85, 86, 87,
+ /* 310 */ 88, 89, 90, 91, 92, 93, 94, 43, 44, 45,
+ /* 320 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ /* 330 */ 56, 57, 152, 157, 152, 196, 196, 16, 96, 97,
+ /* 340 */ 98, 26, 132, 250, 134, 19, 107, 83, 59, 23,
+ /* 350 */ 211, 212, 172, 173, 172, 173, 1, 2, 84, 85,
+ /* 360 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 43,
+ /* 370 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ /* 380 */ 54, 55, 56, 57, 244, 152, 97, 207, 208, 207,
+ /* 390 */ 208, 185, 221, 222, 223, 152, 75, 19, 77, 179,
+ /* 400 */ 180, 23, 93, 94, 228, 172, 173, 231, 188, 152,
+ /* 410 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
+ /* 420 */ 94, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ /* 430 */ 52, 53, 54, 55, 56, 57, 193, 152, 123, 152,
+ /* 440 */ 207, 208, 152, 168, 169, 170, 168, 169, 170, 19,
+ /* 450 */ 160, 22, 23, 23, 164, 119, 120, 172, 173, 172,
+ /* 460 */ 173, 140, 84, 85, 86, 87, 88, 89, 90, 91,
+ /* 470 */ 92, 93, 94, 43, 44, 45, 46, 47, 48, 49,
+ /* 480 */ 50, 51, 52, 53, 54, 55, 56, 57, 99, 22,
+ /* 490 */ 23, 102, 103, 104, 194, 195, 0, 1, 2, 247,
+ /* 500 */ 248, 19, 113, 190, 191, 23, 206, 190, 191, 59,
+ /* 510 */ 225, 152, 83, 152, 84, 85, 86, 87, 88, 89,
+ /* 520 */ 90, 91, 92, 93, 94, 43, 44, 45, 46, 47,
+ /* 530 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ /* 540 */ 90, 181, 152, 108, 109, 110, 96, 97, 98, 115,
+ /* 550 */ 83, 117, 118, 19, 193, 152, 23, 152, 152, 26,
+ /* 560 */ 29, 152, 172, 173, 33, 152, 84, 85, 86, 87,
+ /* 570 */ 88, 89, 90, 91, 92, 93, 94, 43, 44, 45,
+ /* 580 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ /* 590 */ 56, 57, 22, 152, 16, 64, 193, 207, 152, 193,
+ /* 600 */ 12, 7, 8, 9, 152, 108, 109, 110, 19, 152,
+ /* 610 */ 164, 146, 147, 172, 173, 27, 163, 181, 84, 85,
+ /* 620 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 59,
+ /* 630 */ 42, 98, 43, 44, 45, 46, 47, 48, 49, 50,
+ /* 640 */ 51, 52, 53, 54, 55, 56, 57, 238, 22, 196,
+ /* 650 */ 62, 163, 82, 75, 152, 77, 152, 124, 88, 89,
+ /* 660 */ 72, 152, 137, 19, 139, 152, 96, 97, 24, 152,
+ /* 670 */ 152, 101, 138, 84, 85, 86, 87, 88, 89, 90,
+ /* 680 */ 91, 92, 93, 94, 196, 59, 19, 43, 44, 45,
+ /* 690 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ /* 700 */ 56, 57, 132, 133, 134, 152, 193, 219, 245, 246,
+ /* 710 */ 193, 152, 152, 46, 152, 19, 166, 167, 152, 217,
+ /* 720 */ 232, 217, 96, 97, 98, 237, 217, 138, 84, 85,
+ /* 730 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 43,
+ /* 740 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ /* 750 */ 54, 55, 56, 57, 79, 193, 238, 166, 167, 211,
+ /* 760 */ 212, 23, 23, 116, 26, 26, 195, 19, 121, 152,
+ /* 770 */ 217, 152, 152, 152, 107, 100, 217, 206, 163, 112,
+ /* 780 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
+ /* 790 */ 94, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ /* 800 */ 52, 53, 54, 55, 56, 57, 187, 187, 7, 8,
+ /* 810 */ 152, 196, 22, 132, 24, 134, 23, 23, 19, 26,
+ /* 820 */ 26, 23, 152, 23, 26, 23, 26, 59, 26, 163,
+ /* 830 */ 172, 173, 84, 85, 86, 87, 88, 89, 90, 91,
+ /* 840 */ 92, 93, 94, 44, 45, 46, 47, 48, 49, 50,
+ /* 850 */ 51, 52, 53, 54, 55, 56, 57, 152, 26, 238,
+ /* 860 */ 152, 23, 196, 101, 26, 97, 100, 101, 19, 19,
+ /* 870 */ 23, 59, 152, 26, 112, 152, 23, 172, 173, 26,
+ /* 880 */ 172, 173, 19, 84, 85, 86, 87, 88, 89, 90,
+ /* 890 */ 91, 92, 93, 94, 45, 46, 47, 48, 49, 50,
+ /* 900 */ 51, 52, 53, 54, 55, 56, 57, 19, 20, 97,
+ /* 910 */ 22, 23, 207, 163, 23, 163, 132, 26, 134, 23,
+ /* 920 */ 213, 152, 26, 59, 36, 152, 22, 152, 19, 20,
+ /* 930 */ 98, 22, 152, 84, 85, 86, 87, 88, 89, 90,
+ /* 940 */ 91, 92, 93, 94, 94, 36, 196, 59, 196, 99,
+ /* 950 */ 100, 101, 102, 103, 104, 105, 124, 59, 70, 96,
+ /* 960 */ 163, 97, 112, 59, 181, 152, 152, 79, 59, 71,
+ /* 970 */ 82, 19, 26, 152, 152, 152, 88, 89, 152, 70,
+ /* 980 */ 22, 152, 163, 95, 96, 97, 98, 152, 79, 101,
+ /* 990 */ 22, 82, 152, 196, 96, 97, 98, 88, 89, 19,
+ /* 1000 */ 20, 97, 22, 163, 95, 96, 97, 98, 152, 22,
+ /* 1010 */ 101, 24, 172, 173, 152, 196, 36, 59, 22, 152,
+ /* 1020 */ 132, 133, 134, 135, 136, 24, 5, 59, 172, 173,
+ /* 1030 */ 152, 10, 11, 12, 13, 14, 196, 152, 17, 59,
+ /* 1040 */ 210, 132, 133, 134, 135, 136, 59, 207, 96, 22,
+ /* 1050 */ 70, 30, 106, 32, 96, 97, 98, 172, 173, 152,
+ /* 1060 */ 59, 40, 82, 152, 96, 97, 98, 152, 88, 89,
+ /* 1070 */ 90, 186, 59, 22, 191, 95, 96, 97, 98, 172,
+ /* 1080 */ 173, 101, 19, 20, 97, 22, 59, 152, 152, 152,
+ /* 1090 */ 69, 59, 152, 186, 152, 152, 152, 76, 97, 36,
+ /* 1100 */ 79, 80, 19, 20, 53, 22, 152, 172, 173, 96,
+ /* 1110 */ 97, 98, 132, 133, 134, 135, 136, 35, 122, 36,
+ /* 1120 */ 234, 186, 59, 96, 97, 98, 172, 173, 96, 97,
+ /* 1130 */ 98, 152, 233, 70, 152, 114, 152, 124, 210, 210,
+ /* 1140 */ 186, 210, 59, 198, 197, 82, 214, 65, 150, 152,
+ /* 1150 */ 201, 88, 89, 70, 201, 73, 124, 239, 95, 96,
+ /* 1160 */ 97, 98, 141, 239, 101, 82, 169, 170, 176, 152,
+ /* 1170 */ 152, 88, 89, 21, 54, 55, 56, 57, 95, 96,
+ /* 1180 */ 97, 98, 164, 214, 101, 214, 169, 170, 163, 184,
+ /* 1190 */ 180, 175, 227, 111, 175, 132, 133, 134, 135, 136,
+ /* 1200 */ 200, 183, 152, 185, 84, 85, 86, 87, 88, 89,
+ /* 1210 */ 90, 91, 92, 93, 94, 132, 133, 134, 135, 136,
+ /* 1220 */ 12, 196, 172, 173, 175, 152, 198, 230, 152, 155,
+ /* 1230 */ 78, 152, 243, 152, 60, 27, 152, 159, 152, 159,
+ /* 1240 */ 152, 122, 38, 152, 219, 172, 173, 230, 172, 173,
+ /* 1250 */ 42, 172, 173, 172, 173, 103, 172, 173, 172, 173,
+ /* 1260 */ 172, 173, 237, 172, 173, 152, 240, 152, 159, 152,
+ /* 1270 */ 62, 240, 22, 220, 152, 43, 152, 130, 152, 189,
+ /* 1280 */ 152, 18, 152, 18, 192, 172, 173, 172, 173, 172,
+ /* 1290 */ 173, 192, 140, 152, 172, 173, 172, 173, 172, 173,
+ /* 1300 */ 172, 173, 172, 173, 201, 152, 192, 159, 152, 158,
+ /* 1310 */ 192, 152, 201, 172, 173, 152, 220, 152, 189, 152,
+ /* 1320 */ 189, 159, 152, 137, 152, 172, 173, 152, 172, 173,
+ /* 1330 */ 152, 172, 173, 152, 201, 172, 173, 172, 173, 172,
+ /* 1340 */ 173, 152, 172, 173, 172, 173, 152, 172, 173, 152,
+ /* 1350 */ 172, 173, 152, 172, 173, 152, 90, 152, 61, 152,
+ /* 1360 */ 158, 172, 173, 152, 158, 152, 172, 173, 152, 172,
+ /* 1370 */ 173, 152, 172, 173, 236, 172, 173, 172, 173, 172,
+ /* 1380 */ 173, 235, 116, 172, 173, 172, 173, 121, 172, 173,
+ /* 1390 */ 159, 172, 173, 159, 22, 177, 159, 158, 177, 159,
+ /* 1400 */ 158, 107, 174, 174, 174, 63, 182, 106, 182, 174,
+ /* 1410 */ 177, 125, 176, 107, 216, 174, 215, 174, 174, 159,
+ /* 1420 */ 22, 159, 137, 224, 177, 216, 216, 215, 94, 215,
+ /* 1430 */ 177, 216, 215, 129, 126, 128, 127, 25, 162, 26,
+ /* 1440 */ 161, 13, 153, 205, 153, 6, 226, 151, 202, 204,
+ /* 1450 */ 201, 229, 229, 151, 203, 165, 151, 165, 178, 178,
+ /* 1460 */ 165, 4, 3, 22, 142, 15, 81, 16, 23, 23,
+ /* 1470 */ 120, 131, 111, 20, 249, 123, 249, 16, 125, 1,
+ /* 1480 */ 123, 111, 131, 53, 53, 53, 53, 96, 34, 122,
+ /* 1490 */ 1, 5, 22, 107, 246, 140, 67, 26, 74, 41,
+ /* 1500 */ 107, 67, 20, 24, 19, 105, 112, 23, 66, 22,
+ /* 1510 */ 22, 28, 22, 22, 66, 22, 22, 37, 66, 23,
+ /* 1520 */ 23, 23, 116, 23, 22, 26, 122, 26, 23, 23,
+ /* 1530 */ 22, 96, 124, 26, 23, 26, 23, 34, 34, 23,
+ /* 1540 */ 23, 26, 23, 22, 34, 11, 23, 22, 24, 122,
+ /* 1550 */ 23, 22, 26, 22, 24, 23, 23, 15, 23, 22,
+ /* 1560 */ 122, 23, 122, 1, 251, 122,
};
-#define YY_SHIFT_USE_DFLT (1565)
+#define YY_SHIFT_USE_DFLT (1566)
#define YY_SHIFT_COUNT (454)
-#define YY_SHIFT_MIN (-114)
+#define YY_SHIFT_MIN (-84)
#define YY_SHIFT_MAX (1562)
static const short yy_shift_ofst[] = {
- /* 0 */ 5, 1117, 1312, 1128, 1274, 1274, 1274, 1274, 61, -19,
- /* 10 */ 57, 57, 183, 1274, 1274, 1274, 1274, 1274, 1274, 1274,
- /* 20 */ 66, 66, 201, -29, 331, 318, 133, 259, 335, 411,
- /* 30 */ 487, 563, 639, 689, 765, 841, 891, 891, 891, 891,
- /* 40 */ 891, 891, 891, 891, 891, 891, 891, 891, 891, 891,
- /* 50 */ 891, 891, 891, 941, 891, 991, 1041, 1041, 1217, 1274,
- /* 60 */ 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274,
- /* 70 */ 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274,
- /* 80 */ 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274,
- /* 90 */ 1363, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274, 1274,
- /* 100 */ 1274, 1274, 1274, 1274, -70, -47, -47, -47, -47, -47,
- /* 110 */ 24, 11, 146, 296, 524, 444, 529, 529, 296, 3,
- /* 120 */ 2, -30, 1565, 1565, 1565, -17, -17, -17, 145, 145,
- /* 130 */ 497, 497, 265, 603, 653, 296, 296, 296, 296, 296,
- /* 140 */ 296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
- /* 150 */ 296, 296, 296, 296, 296, 701, 1078, 147, 147, 2,
- /* 160 */ 164, 164, 164, 164, 164, 164, 1565, 1565, 1565, 223,
- /* 170 */ 56, 56, 268, 269, 220, 347, 351, 415, 359, 296,
- /* 180 */ 296, 296, 296, 296, 296, 296, 296, 296, 296, 296,
- /* 190 */ 296, 296, 296, 296, 296, 632, 632, 632, 296, 296,
- /* 200 */ 498, 296, 296, 296, 570, 296, 296, 654, 296, 296,
- /* 210 */ 296, 296, 296, 296, 296, 296, 296, 296, 636, 200,
- /* 220 */ 596, 596, 596, 575, -114, 971, 740, 454, 503, 503,
- /* 230 */ 1134, 454, 1134, 353, 588, 628, 762, 503, 189, 762,
- /* 240 */ 762, 916, 330, 668, 1245, 1167, 1167, 1255, 1255, 1167,
- /* 250 */ 1277, 1230, 1172, 1291, 1291, 1291, 1291, 1167, 1310, 1172,
- /* 260 */ 1277, 1230, 1230, 1172, 1167, 1310, 1204, 1299, 1167, 1167,
- /* 270 */ 1310, 1335, 1167, 1310, 1167, 1310, 1335, 1258, 1258, 1258,
- /* 280 */ 1329, 1335, 1258, 1273, 1258, 1329, 1258, 1258, 1256, 1288,
- /* 290 */ 1256, 1288, 1256, 1288, 1256, 1288, 1167, 1375, 1167, 1267,
- /* 300 */ 1335, 1320, 1320, 1335, 1287, 1295, 1294, 1301, 1172, 1407,
- /* 310 */ 1408, 1422, 1422, 1433, 1433, 1433, 1565, 1565, 1565, 1565,
- /* 320 */ 1565, 1565, 1565, 1565, 558, 537, 684, 719, 734, 799,
- /* 330 */ 840, 1019, 14, 1020, 1021, 1025, 1026, 1027, 1070, 1072,
- /* 340 */ 997, 1047, 999, 1079, 1126, 1074, 1141, 694, 819, 1174,
- /* 350 */ 1136, 981, 1444, 1446, 1432, 1313, 1441, 1396, 1449, 1443,
- /* 360 */ 1445, 1347, 1338, 1359, 1348, 1452, 1349, 1457, 1474, 1353,
- /* 370 */ 1346, 1400, 1401, 1402, 1403, 1371, 1387, 1450, 1362, 1485,
- /* 380 */ 1482, 1466, 1382, 1350, 1438, 1467, 1439, 1434, 1458, 1393,
- /* 390 */ 1478, 1483, 1486, 1392, 1404, 1484, 1455, 1488, 1489, 1490,
- /* 400 */ 1492, 1456, 1487, 1493, 1460, 1479, 1494, 1496, 1497, 1495,
- /* 410 */ 1406, 1501, 1502, 1504, 1498, 1405, 1505, 1506, 1435, 1499,
- /* 420 */ 1508, 1409, 1509, 1503, 1510, 1507, 1514, 1509, 1516, 1517,
- /* 430 */ 1518, 1519, 1520, 1522, 1521, 1523, 1525, 1524, 1526, 1527,
- /* 440 */ 1529, 1530, 1526, 1532, 1531, 1533, 1534, 1536, 1427, 1437,
- /* 450 */ 1440, 1442, 1537, 1546, 1562,
+ /* 0 */ 355, 888, 1021, 909, 1063, 1063, 1063, 1063, 20, -19,
+ /* 10 */ 66, 66, 170, 1063, 1063, 1063, 1063, 1063, 1063, 1063,
+ /* 20 */ -7, -7, 36, 73, 69, 27, 118, 222, 274, 326,
+ /* 30 */ 378, 430, 482, 534, 589, 644, 696, 696, 696, 696,
+ /* 40 */ 696, 696, 696, 696, 696, 696, 696, 696, 696, 696,
+ /* 50 */ 696, 696, 696, 748, 696, 799, 849, 849, 980, 1063,
+ /* 60 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063,
+ /* 70 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063,
+ /* 80 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063,
+ /* 90 */ 1083, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063,
+ /* 100 */ 1063, 1063, 1063, 1063, -43, 1120, 1120, 1120, 1120, 1120,
+ /* 110 */ -31, -72, -84, 242, 1152, 667, 210, 210, 242, 309,
+ /* 120 */ 336, -55, 1566, 1566, 1566, 850, 850, 850, 626, 626,
+ /* 130 */ 588, 588, 898, 221, 264, 242, 242, 242, 242, 242,
+ /* 140 */ 242, 242, 242, 242, 242, 242, 242, 242, 242, 242,
+ /* 150 */ 242, 242, 242, 242, 242, 496, 675, 289, 289, 336,
+ /* 160 */ 0, 0, 0, 0, 0, 0, 1566, 1566, 1566, 570,
+ /* 170 */ 98, 98, 958, 389, 450, 968, 1013, 1032, 1027, 242,
+ /* 180 */ 242, 242, 242, 242, 242, 242, 242, 242, 242, 242,
+ /* 190 */ 242, 242, 242, 242, 242, 1082, 1082, 1082, 242, 242,
+ /* 200 */ 533, 242, 242, 242, 987, 242, 242, 1208, 242, 242,
+ /* 210 */ 242, 242, 242, 242, 242, 242, 242, 242, 435, 531,
+ /* 220 */ 1001, 1001, 1001, 832, 434, 1266, 594, 58, 863, 863,
+ /* 230 */ 952, 58, 952, 946, 738, 239, 145, 863, 525, 145,
+ /* 240 */ 145, 315, 647, 790, 1174, 1119, 1119, 1204, 1204, 1119,
+ /* 250 */ 1250, 1232, 1147, 1263, 1263, 1263, 1263, 1119, 1265, 1147,
+ /* 260 */ 1250, 1232, 1232, 1147, 1119, 1265, 1186, 1297, 1119, 1119,
+ /* 270 */ 1265, 1372, 1119, 1265, 1119, 1265, 1372, 1294, 1294, 1294,
+ /* 280 */ 1342, 1372, 1294, 1301, 1294, 1342, 1294, 1294, 1286, 1306,
+ /* 290 */ 1286, 1306, 1286, 1306, 1286, 1306, 1119, 1398, 1119, 1285,
+ /* 300 */ 1372, 1334, 1334, 1372, 1304, 1308, 1307, 1309, 1147, 1412,
+ /* 310 */ 1413, 1428, 1428, 1439, 1439, 1439, 1566, 1566, 1566, 1566,
+ /* 320 */ 1566, 1566, 1566, 1566, 204, 321, 429, 467, 578, 497,
+ /* 330 */ 904, 739, 1051, 793, 794, 798, 800, 802, 838, 768,
+ /* 340 */ 766, 801, 762, 847, 853, 812, 891, 681, 784, 896,
+ /* 350 */ 864, 996, 1457, 1459, 1441, 1322, 1450, 1385, 1451, 1445,
+ /* 360 */ 1446, 1350, 1340, 1361, 1352, 1453, 1353, 1461, 1478, 1357,
+ /* 370 */ 1351, 1430, 1431, 1432, 1433, 1370, 1391, 1454, 1367, 1489,
+ /* 380 */ 1486, 1470, 1386, 1355, 1429, 1471, 1434, 1424, 1458, 1393,
+ /* 390 */ 1479, 1482, 1485, 1394, 1400, 1487, 1442, 1488, 1490, 1484,
+ /* 400 */ 1491, 1448, 1483, 1493, 1452, 1480, 1496, 1497, 1498, 1499,
+ /* 410 */ 1406, 1494, 1500, 1502, 1501, 1404, 1505, 1506, 1435, 1503,
+ /* 420 */ 1508, 1408, 1507, 1504, 1509, 1510, 1511, 1507, 1513, 1516,
+ /* 430 */ 1517, 1515, 1519, 1521, 1534, 1523, 1525, 1524, 1526, 1527,
+ /* 440 */ 1529, 1530, 1526, 1532, 1531, 1533, 1535, 1537, 1427, 1438,
+ /* 450 */ 1440, 1443, 1538, 1542, 1562,
};
-#define YY_REDUCE_USE_DFLT (-174)
+#define YY_REDUCE_USE_DFLT (-144)
#define YY_REDUCE_COUNT (323)
-#define YY_REDUCE_MIN (-173)
-#define YY_REDUCE_MAX (1292)
+#define YY_REDUCE_MIN (-143)
+#define YY_REDUCE_MAX (1305)
static const short yy_reduce_ofst[] = {
- /* 0 */ -119, 1014, 131, 1031, -12, 225, 228, 300, -40, -45,
- /* 10 */ 243, 256, 293, 129, 218, 418, 79, 376, 433, 298,
- /* 20 */ 16, 137, 367, 323, -38, 391, -173, -173, -173, -173,
- /* 30 */ -173, -173, -173, -173, -173, -173, -173, -173, -173, -173,
- /* 40 */ -173, -173, -173, -173, -173, -173, -173, -173, -173, -173,
- /* 50 */ -173, -173, -173, -173, -173, -173, -173, -173, 374, 437,
- /* 60 */ 443, 508, 513, 522, 532, 582, 584, 620, 633, 635,
- /* 70 */ 637, 644, 646, 648, 650, 652, 659, 661, 696, 709,
- /* 80 */ 711, 714, 720, 722, 724, 726, 728, 733, 772, 784,
- /* 90 */ 786, 822, 834, 836, 884, 886, 922, 934, 936, 986,
- /* 100 */ 989, 1008, 1016, 1018, -173, -173, -173, -173, -173, -173,
- /* 110 */ -173, -173, -173, 544, -37, 274, 299, 501, 161, -173,
- /* 120 */ 193, -173, -173, -173, -173, 22, 22, 22, 64, 141,
- /* 130 */ 212, 342, 208, 504, 504, 132, 494, 606, 677, 678,
- /* 140 */ 750, 794, 796, -58, 32, 383, 660, 737, 386, 787,
- /* 150 */ 800, 441, 872, 224, 850, 803, 949, 624, 830, 669,
- /* 160 */ 961, 979, 983, 1011, 1013, 1032, 753, 789, 321, 94,
- /* 170 */ 116, 304, 375, 210, 388, 392, 478, 545, 649, 721,
- /* 180 */ 727, 736, 752, 795, 853, 952, 958, 1004, 1040, 1046,
- /* 190 */ 1049, 1050, 1056, 1059, 1067, 559, 774, 811, 1068, 1080,
- /* 200 */ 938, 1082, 1083, 1088, 962, 1089, 1090, 1052, 1093, 1094,
- /* 210 */ 1095, 388, 1096, 1103, 1104, 1105, 1106, 1107, 965, 998,
- /* 220 */ 1055, 1057, 1058, 938, 1069, 1071, 1120, 1073, 1061, 1062,
- /* 230 */ 1033, 1076, 1039, 1108, 1087, 1099, 1111, 1066, 1054, 1112,
- /* 240 */ 1113, 1091, 1084, 1135, 1060, 1133, 1138, 1064, 1081, 1139,
- /* 250 */ 1100, 1119, 1109, 1124, 1127, 1140, 1142, 1168, 1173, 1132,
- /* 260 */ 1115, 1147, 1148, 1137, 1180, 1182, 1110, 1121, 1188, 1189,
- /* 270 */ 1197, 1181, 1200, 1202, 1205, 1203, 1191, 1192, 1199, 1206,
- /* 280 */ 1207, 1209, 1210, 1211, 1214, 1212, 1218, 1219, 1175, 1183,
- /* 290 */ 1185, 1184, 1186, 1190, 1187, 1196, 1237, 1193, 1253, 1194,
- /* 300 */ 1236, 1195, 1198, 1238, 1213, 1221, 1220, 1227, 1229, 1271,
- /* 310 */ 1275, 1284, 1285, 1289, 1290, 1292, 1201, 1208, 1216, 1279,
- /* 320 */ 1280, 1264, 1268, 1282,
+ /* 0 */ -143, -65, 140, 840, 76, 180, 182, 233, 488, -25,
+ /* 10 */ 12, 16, 59, 885, 907, 935, 390, 705, 954, 285,
+ /* 20 */ 997, 1017, 1018, -118, 1025, 139, 171, 171, 171, 171,
+ /* 30 */ 171, 171, 171, 171, 171, 171, 171, 171, 171, 171,
+ /* 40 */ 171, 171, 171, 171, 171, 171, 171, 171, 171, 171,
+ /* 50 */ 171, 171, 171, 171, 171, 171, 171, 171, -69, 287,
+ /* 60 */ 441, 658, 708, 856, 1050, 1073, 1076, 1079, 1081, 1084,
+ /* 70 */ 1086, 1088, 1091, 1113, 1115, 1117, 1122, 1124, 1126, 1128,
+ /* 80 */ 1130, 1141, 1153, 1156, 1159, 1163, 1165, 1167, 1170, 1172,
+ /* 90 */ 1175, 1178, 1181, 1189, 1194, 1197, 1200, 1203, 1205, 1207,
+ /* 100 */ 1211, 1213, 1216, 1219, 171, 171, 171, 171, 171, 171,
+ /* 110 */ 171, 171, 171, 49, 176, 220, 275, 278, 290, 171,
+ /* 120 */ 300, 171, 171, 171, 171, -85, -85, -85, -28, 77,
+ /* 130 */ 313, 317, -56, 252, 252, 446, -129, 243, 361, 403,
+ /* 140 */ 406, 513, 517, 409, 502, 518, 504, 509, 621, 553,
+ /* 150 */ 562, 619, 559, 93, 620, 465, 453, 550, 591, 571,
+ /* 160 */ 615, 666, 750, 752, 797, 819, 463, 548, -73, 28,
+ /* 170 */ 68, 120, 257, 206, 359, 405, 413, 452, 457, 560,
+ /* 180 */ 566, 617, 670, 720, 723, 769, 773, 775, 780, 813,
+ /* 190 */ 814, 821, 822, 823, 826, 360, 436, 783, 829, 835,
+ /* 200 */ 707, 862, 867, 878, 830, 911, 915, 883, 936, 937,
+ /* 210 */ 940, 359, 942, 943, 944, 979, 982, 984, 886, 899,
+ /* 220 */ 928, 929, 931, 707, 947, 945, 998, 949, 932, 969,
+ /* 230 */ 918, 953, 924, 992, 1005, 1010, 1016, 971, 965, 1019,
+ /* 240 */ 1049, 1000, 1028, 1074, 989, 1078, 1080, 1026, 1031, 1109,
+ /* 250 */ 1053, 1090, 1103, 1092, 1099, 1114, 1118, 1148, 1151, 1111,
+ /* 260 */ 1096, 1129, 1131, 1133, 1162, 1202, 1138, 1146, 1231, 1234,
+ /* 270 */ 1206, 1218, 1237, 1239, 1240, 1242, 1221, 1228, 1229, 1230,
+ /* 280 */ 1224, 1233, 1235, 1236, 1241, 1226, 1243, 1244, 1198, 1201,
+ /* 290 */ 1209, 1212, 1210, 1214, 1215, 1217, 1260, 1199, 1262, 1220,
+ /* 300 */ 1247, 1222, 1223, 1253, 1238, 1245, 1251, 1246, 1249, 1276,
+ /* 310 */ 1279, 1289, 1291, 1296, 1302, 1305, 1225, 1227, 1248, 1290,
+ /* 320 */ 1292, 1280, 1281, 1295,
};
static const YYACTIONTYPE yy_default[] = {
/* 0 */ 1270, 1260, 1260, 1260, 1193, 1193, 1193, 1193, 1260, 1088,
@@ -137572,73 +137940,87 @@ static const YYACTIONTYPE yy_default[] = {
static const YYCODETYPE yyFallback[] = {
0, /* $ => nothing */
0, /* SEMI => nothing */
- 27, /* EXPLAIN => ID */
- 27, /* QUERY => ID */
- 27, /* PLAN => ID */
- 27, /* BEGIN => ID */
+ 59, /* EXPLAIN => ID */
+ 59, /* QUERY => ID */
+ 59, /* PLAN => ID */
+ 59, /* BEGIN => ID */
0, /* TRANSACTION => nothing */
- 27, /* DEFERRED => ID */
- 27, /* IMMEDIATE => ID */
- 27, /* EXCLUSIVE => ID */
+ 59, /* DEFERRED => ID */
+ 59, /* IMMEDIATE => ID */
+ 59, /* EXCLUSIVE => ID */
0, /* COMMIT => nothing */
- 27, /* END => ID */
- 27, /* ROLLBACK => ID */
- 27, /* SAVEPOINT => ID */
- 27, /* RELEASE => ID */
+ 59, /* END => ID */
+ 59, /* ROLLBACK => ID */
+ 59, /* SAVEPOINT => ID */
+ 59, /* RELEASE => ID */
0, /* TO => nothing */
0, /* TABLE => nothing */
0, /* CREATE => nothing */
- 27, /* IF => ID */
+ 59, /* IF => ID */
0, /* NOT => nothing */
0, /* EXISTS => nothing */
- 27, /* TEMP => ID */
+ 59, /* TEMP => ID */
0, /* LP => nothing */
0, /* RP => nothing */
0, /* AS => nothing */
- 27, /* WITHOUT => ID */
+ 59, /* WITHOUT => ID */
0, /* COMMA => nothing */
+ 59, /* ABORT => ID */
+ 59, /* ACTION => ID */
+ 59, /* AFTER => ID */
+ 59, /* ANALYZE => ID */
+ 59, /* ASC => ID */
+ 59, /* ATTACH => ID */
+ 59, /* BEFORE => ID */
+ 59, /* BY => ID */
+ 59, /* CASCADE => ID */
+ 59, /* CAST => ID */
+ 59, /* CONFLICT => ID */
+ 59, /* DATABASE => ID */
+ 59, /* DESC => ID */
+ 59, /* DETACH => ID */
+ 59, /* EACH => ID */
+ 59, /* FAIL => ID */
+ 0, /* OR => nothing */
+ 0, /* AND => nothing */
+ 0, /* IS => nothing */
+ 59, /* MATCH => ID */
+ 59, /* LIKE_KW => ID */
+ 0, /* BETWEEN => nothing */
+ 0, /* IN => nothing */
+ 0, /* ISNULL => nothing */
+ 0, /* NOTNULL => nothing */
+ 0, /* NE => nothing */
+ 0, /* EQ => nothing */
+ 0, /* GT => nothing */
+ 0, /* LE => nothing */
+ 0, /* LT => nothing */
+ 0, /* GE => nothing */
+ 0, /* ESCAPE => nothing */
0, /* ID => nothing */
- 27, /* ABORT => ID */
- 27, /* ACTION => ID */
- 27, /* AFTER => ID */
- 27, /* ANALYZE => ID */
- 27, /* ASC => ID */
- 27, /* ATTACH => ID */
- 27, /* BEFORE => ID */
- 27, /* BY => ID */
- 27, /* CASCADE => ID */
- 27, /* CAST => ID */
- 27, /* COLUMNKW => ID */
- 27, /* CONFLICT => ID */
- 27, /* DATABASE => ID */
- 27, /* DESC => ID */
- 27, /* DETACH => ID */
- 27, /* EACH => ID */
- 27, /* FAIL => ID */
- 27, /* FOR => ID */
- 27, /* IGNORE => ID */
- 27, /* INITIALLY => ID */
- 27, /* INSTEAD => ID */
- 27, /* LIKE_KW => ID */
- 27, /* MATCH => ID */
- 27, /* NO => ID */
- 27, /* KEY => ID */
- 27, /* OF => ID */
- 27, /* OFFSET => ID */
- 27, /* PRAGMA => ID */
- 27, /* RAISE => ID */
- 27, /* RECURSIVE => ID */
- 27, /* REPLACE => ID */
- 27, /* RESTRICT => ID */
- 27, /* ROW => ID */
- 27, /* TRIGGER => ID */
- 27, /* VACUUM => ID */
- 27, /* VIEW => ID */
- 27, /* VIRTUAL => ID */
- 27, /* WITH => ID */
- 27, /* REINDEX => ID */
- 27, /* RENAME => ID */
- 27, /* CTIME_KW => ID */
+ 59, /* COLUMNKW => ID */
+ 59, /* FOR => ID */
+ 59, /* IGNORE => ID */
+ 59, /* INITIALLY => ID */
+ 59, /* INSTEAD => ID */
+ 59, /* NO => ID */
+ 59, /* KEY => ID */
+ 59, /* OF => ID */
+ 59, /* OFFSET => ID */
+ 59, /* PRAGMA => ID */
+ 59, /* RAISE => ID */
+ 59, /* RECURSIVE => ID */
+ 59, /* REPLACE => ID */
+ 59, /* RESTRICT => ID */
+ 59, /* ROW => ID */
+ 59, /* TRIGGER => ID */
+ 59, /* VACUUM => ID */
+ 59, /* VIEW => ID */
+ 59, /* VIRTUAL => ID */
+ 59, /* WITH => ID */
+ 59, /* REINDEX => ID */
+ 59, /* RENAME => ID */
+ 59, /* CTIME_KW => ID */
};
#endif /* YYFALLBACK */
@@ -137731,21 +138113,21 @@ static const char *const yyTokenName[] = {
"ROLLBACK", "SAVEPOINT", "RELEASE", "TO",
"TABLE", "CREATE", "IF", "NOT",
"EXISTS", "TEMP", "LP", "RP",
- "AS", "WITHOUT", "COMMA", "ID",
- "ABORT", "ACTION", "AFTER", "ANALYZE",
- "ASC", "ATTACH", "BEFORE", "BY",
- "CASCADE", "CAST", "COLUMNKW", "CONFLICT",
- "DATABASE", "DESC", "DETACH", "EACH",
- "FAIL", "FOR", "IGNORE", "INITIALLY",
- "INSTEAD", "LIKE_KW", "MATCH", "NO",
- "KEY", "OF", "OFFSET", "PRAGMA",
- "RAISE", "RECURSIVE", "REPLACE", "RESTRICT",
- "ROW", "TRIGGER", "VACUUM", "VIEW",
- "VIRTUAL", "WITH", "REINDEX", "RENAME",
- "CTIME_KW", "ANY", "OR", "AND",
- "IS", "BETWEEN", "IN", "ISNULL",
- "NOTNULL", "NE", "EQ", "GT",
- "LE", "LT", "GE", "ESCAPE",
+ "AS", "WITHOUT", "COMMA", "ABORT",
+ "ACTION", "AFTER", "ANALYZE", "ASC",
+ "ATTACH", "BEFORE", "BY", "CASCADE",
+ "CAST", "CONFLICT", "DATABASE", "DESC",
+ "DETACH", "EACH", "FAIL", "OR",
+ "AND", "IS", "MATCH", "LIKE_KW",
+ "BETWEEN", "IN", "ISNULL", "NOTNULL",
+ "NE", "EQ", "GT", "LE",
+ "LT", "GE", "ESCAPE", "ID",
+ "COLUMNKW", "FOR", "IGNORE", "INITIALLY",
+ "INSTEAD", "NO", "KEY", "OF",
+ "OFFSET", "PRAGMA", "RAISE", "RECURSIVE",
+ "REPLACE", "RESTRICT", "ROW", "TRIGGER",
+ "VACUUM", "VIEW", "VIRTUAL", "WITH",
+ "REINDEX", "RENAME", "CTIME_KW", "ANY",
"BITAND", "BITOR", "LSHIFT", "RSHIFT",
"PLUS", "MINUS", "STAR", "SLASH",
"REM", "CONCAT", "COLLATE", "BITNOT",
@@ -141798,11 +142180,13 @@ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
*/
SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; }
-/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a
+/* IMPLEMENTATION-OF: R-25063-23286 The sqlite3_sourceid() function returns a
** pointer to a string constant whose value is the same as the
-** SQLITE_SOURCE_ID C preprocessor macro.
+** 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.
*/
-SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
+/* SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } */
/* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function
** returns an integer equal to SQLITE_VERSION_NUMBER.
@@ -142187,14 +142571,8 @@ SQLITE_API int sqlite3_config(int op, ...){
sqlite3GlobalConfig.bMemstat = va_arg(ap, int);
break;
}
- case SQLITE_CONFIG_SCRATCH: {
- /* EVIDENCE-OF: R-08404-60887 There are three arguments to
- ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from
- ** which the scratch allocations will be drawn, the size of each scratch
- ** allocation (sz), and the maximum number of scratch allocations (N). */
- sqlite3GlobalConfig.pScratch = va_arg(ap, void*);
- sqlite3GlobalConfig.szScratch = va_arg(ap, int);
- sqlite3GlobalConfig.nScratch = va_arg(ap, int);
+ case SQLITE_CONFIG_SMALL_MALLOC: {
+ sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int);
break;
}
case SQLITE_CONFIG_PAGECACHE: {
@@ -142415,7 +142793,8 @@ SQLITE_API int sqlite3_config(int op, ...){
static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
#ifndef SQLITE_OMIT_LOOKASIDE
void *pStart;
- if( db->lookaside.nOut ){
+
+ if( sqlite3LookasideUsed(db,0)>0 ){
return SQLITE_BUSY;
}
/* Free any existing lookaside buffer for this handle before
@@ -142443,16 +142822,18 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
pStart = pBuf;
}
db->lookaside.pStart = pStart;
+ db->lookaside.pInit = 0;
db->lookaside.pFree = 0;
db->lookaside.sz = (u16)sz;
if( pStart ){
int i;
LookasideSlot *p;
assert( sz > (int)sizeof(LookasideSlot*) );
+ db->lookaside.nSlot = cnt;
p = (LookasideSlot*)pStart;
for(i=cnt-1; i>=0; i--){
- p->pNext = db->lookaside.pFree;
- db->lookaside.pFree = p;
+ p->pNext = db->lookaside.pInit;
+ db->lookaside.pInit = p;
p = (LookasideSlot*)&((u8*)p)[sz];
}
db->lookaside.pEnd = p;
@@ -142463,6 +142844,7 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
db->lookaside.pEnd = db;
db->lookaside.bDisable = 1;
db->lookaside.bMalloced = 0;
+ db->lookaside.nSlot = 0;
}
#endif /* SQLITE_OMIT_LOOKASIDE */
return SQLITE_OK;
@@ -142575,7 +142957,7 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
if( aFlagOp[i].op==op ){
int onoff = va_arg(ap, int);
int *pRes = va_arg(ap, int*);
- int oldFlags = db->flags;
+ u32 oldFlags = db->flags;
if( onoff>0 ){
db->flags |= aFlagOp[i].mask;
}else if( onoff==0 ){
@@ -142982,7 +143364,7 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
sqlite3_mutex_leave(db->mutex);
db->magic = SQLITE_MAGIC_CLOSED;
sqlite3_mutex_free(db->mutex);
- assert( db->lookaside.nOut==0 ); /* Fails on a lookaside memory leak */
+ assert( sqlite3LookasideUsed(db,0)==0 );
if( db->lookaside.bMalloced ){
sqlite3_free(db->lookaside.pStart);
}
@@ -143010,7 +143392,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
** the database rollback and schema reset, which can cause false
** corruption reports in some cases. */
sqlite3BtreeEnterAll(db);
- schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0;
+ schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0;
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
@@ -143024,7 +143406,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
sqlite3VtabRollback(db);
sqlite3EndBenignMalloc();
- if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
+ if( (db->mDbFlags&DBFLAG_SchemaChange)!=0 && db->init.busy==0 ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
}
@@ -143926,7 +144308,8 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
** checkpointed. If an error is encountered it is returned immediately -
** no attempt is made to checkpoint any remaining databases.
**
-** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
+** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART
+** or TRUNCATE.
*/
SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){
int rc = SQLITE_OK; /* Return code */
@@ -144812,6 +145195,12 @@ static int openDatabase(
}
#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);
@@ -145471,7 +145860,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
** This action provides a run-time test to see how the ALWAYS and
** NEVER macros were defined at compile-time.
**
- ** The return value is ALWAYS(X).
+ ** The return value is ALWAYS(X) if X is true, or 0 if X is false.
**
** The recommended test is X==2. If the return value is 2, that means
** ALWAYS() and NEVER() are both no-op pass-through macros, which is the
@@ -145494,7 +145883,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
*/
case SQLITE_TESTCTRL_ALWAYS: {
int x = va_arg(ap,int);
- rc = ALWAYS(x);
+ rc = x ? ALWAYS(x) : 0;
break;
}
@@ -145561,22 +145950,6 @@ SQLITE_API int sqlite3_test_control(int op, ...){
}
#endif
- /* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree);
- **
- ** Pass pFree into sqlite3ScratchFree().
- ** If sz>0 then allocate a scratch buffer into pNew.
- */
- case SQLITE_TESTCTRL_SCRATCHMALLOC: {
- void *pFree, **ppNew;
- int sz;
- sz = va_arg(ap, int);
- ppNew = va_arg(ap, void**);
- pFree = va_arg(ap, void*);
- if( sz ) *ppNew = sqlite3ScratchMalloc(sz);
- sqlite3ScratchFree(pFree);
- break;
- }
-
/* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
**
** If parameter onoff is non-zero, configure the wrappers so that all
@@ -145718,7 +146091,7 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(
){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
sqlite3_int64 v;
- if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){
+ if( z && sqlite3DecOrHexToI64(z, &v)==0 ){
bDflt = v;
}
return bDflt;
@@ -168313,7 +168686,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
int rc; /* Return code */
RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */
int iCell; /* Index of iDelete cell in pLeaf */
- RtreeNode *pRoot; /* Root node of rtree structure */
+ RtreeNode *pRoot = 0; /* Root node of rtree structure */
/* Obtain a reference to the root node to initialize Rtree.iDepth */
@@ -168874,7 +169247,7 @@ static int getNodeSize(
if( rc!=SQLITE_OK ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}else if( pRtree->iNodeSize<(512-64) ){
- rc = SQLITE_CORRUPT;
+ rc = SQLITE_CORRUPT_VTAB;
*pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"",
pRtree->zName);
}
@@ -170497,6 +170870,28 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
);
/*
+** Configure a limit for the amount of temp space that may be used by
+** the RBU handle passed as the first argument. The new limit is specified
+** in bytes by the second parameter. If it is positive, the limit is updated.
+** If the second parameter to this function is passed zero, then the limit
+** 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
+** indicates unlimited).
+**
+** If the temp space limit is exceeded during operation, an SQLITE_FULL
+** error is returned.
+*/
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64);
+
+/*
+** 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
** connection to access the target and rbu update databases. This
** API allows the application direct access to these database handles.
@@ -170622,7 +171017,7 @@ SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
** table exists but is not correctly populated, the value of the *pnOne
** output variable during stage 1 is undefined.
*/
-SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo);
+SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
/*
** Obtain an indication as to the current stage of an RBU update or vacuum.
@@ -170732,6 +171127,13 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
/* Maximum number of prepared UPDATE statements held by this module */
#define SQLITE_RBU_UPDATE_CACHESIZE 16
+/* Delta checksums disabled by default. Compile with -DRBU_ENABLE_DELTA_CKSUM
+** to enable checksum verification.
+*/
+#ifndef RBU_ENABLE_DELTA_CKSUM
+# define RBU_ENABLE_DELTA_CKSUM 0
+#endif
+
/*
** Swap two objects of type TYPE.
*/
@@ -171007,6 +171409,8 @@ struct sqlite3rbu {
int pgsz;
u8 *aBuf;
i64 iWalCksum;
+ i64 szTemp; /* Current size of all temp files in use */
+ i64 szTempLimit; /* Total size limit for temp files */
/* Used in RBU vacuum mode only */
int nRbu; /* Number of RBU VFS in the stack */
@@ -171015,23 +171419,33 @@ struct sqlite3rbu {
/*
** An rbu VFS is implemented using an instance of this structure.
+**
+** Variable pRbu is only non-NULL for automatically created RBU VFS objects.
+** It is NULL for RBU VFS objects created explicitly using
+** sqlite3rbu_create_vfs(). It is used to track the total amount of temp
+** space used by the RBU handle.
*/
struct rbu_vfs {
sqlite3_vfs base; /* rbu VFS shim methods */
sqlite3_vfs *pRealVfs; /* Underlying VFS */
sqlite3_mutex *mutex; /* Mutex to protect pMain */
+ sqlite3rbu *pRbu; /* Owner RBU object */
rbu_file *pMain; /* Linked list of main db files */
};
/*
** Each file opened by an rbu VFS is represented by an instance of
** the following structure.
+**
+** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable
+** "sz" is set to the current size of the database file.
*/
struct rbu_file {
sqlite3_file base; /* sqlite3_file methods */
sqlite3_file *pReal; /* Underlying file handle */
rbu_vfs *pRbuVfs; /* Pointer to the rbu_vfs object */
sqlite3rbu *pRbu; /* Pointer to rbu object (rbu target only) */
+ i64 sz; /* Size of file in bytes (temp only) */
int openFlags; /* Flags this file was opened with */
u32 iCookie; /* Cookie value for main db files */
@@ -171094,6 +171508,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
return v;
}
+#if RBU_ENABLE_DELTA_CKSUM
/*
** Compute a 32-bit checksum on the N-byte buffer. Return the result.
*/
@@ -171128,6 +171543,7 @@ static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){
}
return sum3;
}
+#endif
/*
** Apply a delta.
@@ -171158,7 +171574,7 @@ static int rbuDeltaApply(
){
unsigned int limit;
unsigned int total = 0;
-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
+#if RBU_ENABLE_DELTA_CKSUM
char *zOrigOut = zOut;
#endif
@@ -171213,7 +171629,7 @@ static int rbuDeltaApply(
case ';': {
zDelta++; lenDelta--;
zOut[0] = 0;
-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
+#if RBU_ENABLE_DELTA_CKSUM
if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){
/* ERROR: bad checksum */
return -1;
@@ -174045,6 +174461,7 @@ static void rbuCreateVfs(sqlite3rbu *p){
sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
assert( pVfs );
p->zVfsName = pVfs->zName;
+ ((rbu_vfs*)pVfs)->pRbu = p;
}
}
@@ -174417,6 +174834,7 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
/* Close the open database handle and VFS object. */
sqlite3_close(p->dbRbu);
sqlite3_close(p->dbMain);
+ assert( p->szTemp==0 );
rbuDeleteVfs(p);
sqlite3_free(p->aBuf);
sqlite3_free(p->aFrame);
@@ -174604,6 +175022,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
*/
static void rbuUnlockShm(rbu_file *p){
+ assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
if( p->pRbu ){
int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock;
int i;
@@ -174617,6 +175036,18 @@ static void rbuUnlockShm(rbu_file *p){
}
/*
+*/
+static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){
+ sqlite3rbu *pRbu = pFd->pRbu;
+ i64 nDiff = nNew - pFd->sz;
+ pRbu->szTemp += nDiff;
+ pFd->sz = nNew;
+ assert( pRbu->szTemp>=0 );
+ if( pRbu->szTempLimit && pRbu->szTemp>pRbu->szTempLimit ) return SQLITE_FULL;
+ return SQLITE_OK;
+}
+
+/*
** Close an rbu file.
*/
static int rbuVfsClose(sqlite3_file *pFile){
@@ -174641,6 +175072,9 @@ static int rbuVfsClose(sqlite3_file *pFile){
rbuUnlockShm(p);
p->pReal->pMethods->xShmUnmap(p->pReal, 0);
}
+ else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
+ rbuUpdateTempSize(p, 0);
+ }
/* Close the underlying file handle */
rc = p->pReal->pMethods->xClose(p->pReal);
@@ -174758,11 +175192,19 @@ static int rbuVfsWrite(
assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
rc = rbuCaptureDbWrite(p->pRbu, iOfst);
}else{
- if( pRbu && pRbu->eStage==RBU_STAGE_OAL
- && (p->openFlags & SQLITE_OPEN_WAL)
- && iOfst>=pRbu->iOalSz
- ){
- pRbu->iOalSz = iAmt + iOfst;
+ if( pRbu ){
+ if( pRbu->eStage==RBU_STAGE_OAL
+ && (p->openFlags & SQLITE_OPEN_WAL)
+ && iOfst>=pRbu->iOalSz
+ ){
+ pRbu->iOalSz = iAmt + iOfst;
+ }else if( p->openFlags & SQLITE_OPEN_DELETEONCLOSE ){
+ i64 szNew = iAmt+iOfst;
+ if( szNew>p->sz ){
+ rc = rbuUpdateTempSize(p, szNew);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+ }
}
rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
@@ -174781,6 +175223,10 @@ static int rbuVfsWrite(
*/
static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
rbu_file *p = (rbu_file*)pFile;
+ if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
+ int rc = rbuUpdateTempSize(p, size);
+ if( rc!=SQLITE_OK ) return rc;
+ }
return p->pReal->pMethods->xTruncate(p->pReal, size);
}
@@ -175170,6 +175616,8 @@ static int rbuVfsOpen(
pDb->pWalFd = pFd;
}
}
+ }else{
+ pFd->pRbu = pRbuVfs->pRbu;
}
if( oflags & SQLITE_OPEN_MAIN_DB
@@ -175246,7 +175694,9 @@ static int rbuVfsAccess(
if( *pResOut ){
rc = SQLITE_CANTOPEN;
}else{
- *pResOut = 1;
+ sqlite3_int64 sz = 0;
+ rc = rbuVfsFileSize(&pDb->base, &sz);
+ *pResOut = (sz>0);
}
}
}
@@ -175435,6 +175885,20 @@ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
return rc;
}
+/*
+** Configure the aggregate temp file size limit for this RBU handle.
+*/
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu *pRbu, sqlite3_int64 n){
+ if( n>=0 ){
+ pRbu->szTempLimit = n;
+ }
+ return pRbu->szTempLimit;
+}
+
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){
+ return pRbu->szTemp;
+}
+
/**************************************************************************/
@@ -176149,6 +176613,338 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
/************** End of dbstat.c **********************************************/
+/************** Begin file dbpage.c ******************************************/
+/*
+** 2017-10-11
+**
+** 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 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
+** uncommitted changes and changes recorded in the WAL file are correctly
+** retrieved.
+**
+** Usage example:
+**
+** SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
+**
+** This is an eponymous virtual table so it does not need to be created before
+** use. The optional argument to the sqlite_dbpage() table name is the
+** schema for the database file that is to be read. The default schema is
+** "main".
+**
+** The data field of sqlite_dbpage table can be updated. The new
+** value must be a BLOB which is the correct page size, otherwise the
+** update fails. Rows may not be deleted or inserted.
+*/
+
+/* #include "sqliteInt.h" ** Requires access to internal data structures ** */
+#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
+ && !defined(SQLITE_OMIT_VIRTUALTABLE)
+
+typedef struct DbpageTable DbpageTable;
+typedef struct DbpageCursor DbpageCursor;
+
+struct DbpageCursor {
+ sqlite3_vtab_cursor base; /* Base class. Must be first */
+ int pgno; /* Current page number */
+ int mxPgno; /* Last page to visit on this scan */
+};
+
+struct DbpageTable {
+ sqlite3_vtab base; /* Base class. Must be first */
+ sqlite3 *db; /* The database */
+ Pager *pPager; /* Pager being read/written */
+ int iDb; /* Index of database to analyze */
+ int szPage; /* Size of each page in bytes */
+ int nPage; /* Number of pages in the file */
+};
+
+/*
+** Connect to or create a dbpagevfs virtual table.
+*/
+static int dbpageConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ DbpageTable *pTab = 0;
+ int rc = SQLITE_OK;
+ int iDb;
+
+ if( argc>=4 ){
+ Token nm;
+ sqlite3TokenInit(&nm, (char*)argv[3]);
+ iDb = sqlite3FindDb(db, &nm);
+ if( iDb<0 ){
+ *pzErr = sqlite3_mprintf("no such schema: %s", argv[3]);
+ return SQLITE_ERROR;
+ }
+ }else{
+ iDb = 0;
+ }
+ 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));
+ if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
+ }
+
+ assert( rc==SQLITE_OK || pTab==0 );
+ if( rc==SQLITE_OK ){
+ Btree *pBt = db->aDb[iDb].pBt;
+ memset(pTab, 0, sizeof(DbpageTable));
+ pTab->db = db;
+ pTab->iDb = iDb;
+ pTab->pPager = pBt ? sqlite3BtreePager(pBt) : 0;
+ }
+
+ *ppVtab = (sqlite3_vtab*)pTab;
+ return rc;
+}
+
+/*
+** Disconnect from or destroy a dbpagevfs virtual table.
+*/
+static int dbpageDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** idxNum:
+**
+** 0 full table scan
+** 1 pgno=?1
+*/
+static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+ int i;
+ pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
+ if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ pIdxInfo->estimatedRows = 1;
+ pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
+ pIdxInfo->estimatedCost = 1.0;
+ pIdxInfo->idxNum = 1;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ break;
+ }
+ }
+ if( pIdxInfo->nOrderBy>=1
+ && pIdxInfo->aOrderBy[0].iColumn<=0
+ && pIdxInfo->aOrderBy[0].desc==0
+ ){
+ pIdxInfo->orderByConsumed = 1;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Open a new dbpagevfs cursor.
+*/
+static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ DbpageCursor *pCsr;
+
+ pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
+ if( pCsr==0 ){
+ return SQLITE_NOMEM_BKPT;
+ }else{
+ memset(pCsr, 0, sizeof(DbpageCursor));
+ pCsr->base.pVtab = pVTab;
+ pCsr->pgno = -1;
+ }
+
+ *ppCursor = (sqlite3_vtab_cursor *)pCsr;
+ return SQLITE_OK;
+}
+
+/*
+** Close a dbpagevfs cursor.
+*/
+static int dbpageClose(sqlite3_vtab_cursor *pCursor){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/*
+** Move a dbpagevfs cursor to the next entry in the file.
+*/
+static int dbpageNext(sqlite3_vtab_cursor *pCursor){
+ int rc = SQLITE_OK;
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ pCsr->pgno++;
+ return rc;
+}
+
+static int dbpageEof(sqlite3_vtab_cursor *pCursor){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ return pCsr->pgno > pCsr->mxPgno;
+}
+
+static int dbpageFilter(
+ sqlite3_vtab_cursor *pCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
+ int rc = SQLITE_OK;
+ Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
+
+ pTab->szPage = sqlite3BtreeGetPageSize(pBt);
+ pTab->nPage = sqlite3BtreeLastPage(pBt);
+ if( idxNum==1 ){
+ pCsr->pgno = sqlite3_value_int(argv[0]);
+ if( pCsr->pgno<1 || pCsr->pgno>pTab->nPage ){
+ pCsr->pgno = 1;
+ pCsr->mxPgno = 0;
+ }else{
+ pCsr->mxPgno = pCsr->pgno;
+ }
+ }else{
+ pCsr->pgno = 1;
+ pCsr->mxPgno = pTab->nPage;
+ }
+ return rc;
+}
+
+static int dbpageColumn(
+ sqlite3_vtab_cursor *pCursor,
+ sqlite3_context *ctx,
+ int i
+){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
+ int rc = SQLITE_OK;
+ switch( i ){
+ case 0: { /* pgno */
+ sqlite3_result_int(ctx, pCsr->pgno);
+ break;
+ }
+ case 1: { /* data */
+ DbPage *pDbPage = 0;
+ rc = sqlite3PagerGet(pTab->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pTab->szPage,
+ SQLITE_TRANSIENT);
+ }
+ sqlite3PagerUnref(pDbPage);
+ break;
+ }
+ default: { /* schema */
+ sqlite3 *db = sqlite3_context_db_handle(ctx);
+ sqlite3_result_text(ctx, db->aDb[pTab->iDb].zDbSName, -1, SQLITE_STATIC);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ *pRowid = pCsr->pgno;
+ return SQLITE_OK;
+}
+
+static int dbpageUpdate(
+ sqlite3_vtab *pVtab,
+ int argc,
+ sqlite3_value **argv,
+ sqlite_int64 *pRowid
+){
+ DbpageTable *pTab = (DbpageTable *)pVtab;
+ int pgno;
+ DbPage *pDbPage = 0;
+ int rc = SQLITE_OK;
+ char *zErr = 0;
+
+ if( argc==1 ){
+ zErr = "cannot delete";
+ goto update_fail;
+ }
+ pgno = sqlite3_value_int(argv[0]);
+ if( pgno<1 || pgno>pTab->nPage ){
+ zErr = "bad page number";
+ goto update_fail;
+ }
+ if( sqlite3_value_int(argv[1])!=pgno ){
+ zErr = "cannot insert";
+ goto update_fail;
+ }
+ if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
+ || sqlite3_value_bytes(argv[3])!=pTab->szPage
+ ){
+ zErr = "bad page value";
+ goto update_fail;
+ }
+ rc = sqlite3PagerGet(pTab->pPager, pgno, (DbPage**)&pDbPage, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerWrite(pDbPage);
+ if( rc==SQLITE_OK ){
+ memcpy(sqlite3PagerGetData(pDbPage),
+ sqlite3_value_blob(argv[3]),
+ pTab->szPage);
+ }
+ }
+ sqlite3PagerUnref(pDbPage);
+ return rc;
+
+update_fail:
+ sqlite3_free(pVtab->zErrMsg);
+ pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
+ return SQLITE_ERROR;
+}
+
+/*
+** Invoke this routine to register the "dbpage" virtual table module
+*/
+SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
+ static sqlite3_module dbpage_module = {
+ 0, /* iVersion */
+ dbpageConnect, /* xCreate */
+ dbpageConnect, /* xConnect */
+ dbpageBestIndex, /* xBestIndex */
+ dbpageDisconnect, /* xDisconnect */
+ dbpageDisconnect, /* xDestroy */
+ dbpageOpen, /* xOpen - open a cursor */
+ dbpageClose, /* xClose - close a cursor */
+ dbpageFilter, /* xFilter - configure scan constraints */
+ dbpageNext, /* xNext - advance a cursor */
+ dbpageEof, /* xEof - check for end of scan */
+ dbpageColumn, /* xColumn - read data */
+ dbpageRowid, /* xRowid - read data */
+ dbpageUpdate, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ };
+ return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
+}
+#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
+SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
+#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
+
+/************** End of dbpage.c **********************************************/
/************** Begin file sqlite3session.c **********************************/
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
@@ -184739,7 +185535,8 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
** fts5YY_MAX_SHIFT Maximum value for shift actions
** fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
** fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
-** fts5YY_MIN_REDUCE Maximum value for reduce actions
+** fts5YY_MIN_REDUCE Minimum value for reduce actions
+** fts5YY_MAX_REDUCE Maximum value for reduce actions
** fts5YY_ERROR_ACTION The fts5yy_action[] code for syntax error
** fts5YY_ACCEPT_ACTION The fts5yy_action[] code for accept
** fts5YY_NO_ACTION The fts5yy_action[] code for no-op
@@ -200474,7 +201271,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2017-07-19 19:48:40 0a5e1c04d9d07bb7fd6546a9ddac1bf42b19ea19c2b79570aea6cd4226887a27", -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx, "fts5: 2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de48827", -1, SQLITE_TRANSIENT);
}
static int fts5Init(sqlite3 *db){
@@ -203702,6 +204499,11 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){
** 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 in the database.
+**
+** instance:
+** CREATE TABLE vocab(term, doc, col, offset, PRIMARY KEY(<all-fields>));
+**
+** One row for each term instance in the database.
*/
@@ -203717,7 +204519,7 @@ struct Fts5VocabTable {
char *zFts5Db; /* Db containing fts5 table */
sqlite3 *db; /* Database handle */
Fts5Global *pGlobal; /* FTS5 global object for this database */
- int eType; /* FTS5_VOCAB_COL or ROW */
+ int eType; /* FTS5_VOCAB_COL, ROW or INSTANCE */
};
struct Fts5VocabCursor {
@@ -203737,16 +204539,22 @@ struct Fts5VocabCursor {
i64 *aCnt;
i64 *aDoc;
- /* Output values used by 'row' and 'col' tables */
+ /* Output values used by all tables. */
i64 rowid; /* This table's current rowid value */
Fts5Buffer term; /* Current value of 'term' column */
+
+ /* Output values Used by 'instance' tables only */
+ i64 iInstPos;
+ int iInstOff;
};
-#define FTS5_VOCAB_COL 0
-#define FTS5_VOCAB_ROW 1
+#define FTS5_VOCAB_COL 0
+#define FTS5_VOCAB_ROW 1
+#define FTS5_VOCAB_INSTANCE 2
#define FTS5_VOCAB_COL_SCHEMA "term, col, doc, cnt"
#define FTS5_VOCAB_ROW_SCHEMA "term, doc, cnt"
+#define FTS5_VOCAB_INST_SCHEMA "term, doc, col, offset"
/*
** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
@@ -203774,6 +204582,9 @@ static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){
if( sqlite3_stricmp(zCopy, "row")==0 ){
*peType = FTS5_VOCAB_ROW;
}else
+ if( sqlite3_stricmp(zCopy, "instance")==0 ){
+ *peType = FTS5_VOCAB_INSTANCE;
+ }else
{
*pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy);
rc = SQLITE_ERROR;
@@ -203834,7 +204645,8 @@ static int fts5VocabInitVtab(
){
const char *azSchema[] = {
"CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")",
- "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")"
+ "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")",
+ "CREATE TABlE vocab(" FTS5_VOCAB_INST_SCHEMA ")"
};
Fts5VocabTable *pRet = 0;
@@ -203908,6 +204720,15 @@ static int fts5VocabCreateMethod(
/*
** Implementation of the xBestIndex method.
+**
+** Only constraints of the form:
+**
+** term <= ?
+** term == ?
+** term >= ?
+**
+** are interpreted. Less-than and less-than-or-equal are treated
+** identically, as are greater-than and greater-than-or-equal.
*/
static int fts5VocabBestIndexMethod(
sqlite3_vtab *pUnused,
@@ -204051,6 +204872,54 @@ static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){
return SQLITE_OK;
}
+static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){
+ int rc = SQLITE_OK;
+
+ if( sqlite3Fts5IterEof(pCsr->pIter) ){
+ pCsr->bEof = 1;
+ }else{
+ const char *zTerm;
+ int nTerm;
+ zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
+ if( pCsr->nLeTerm>=0 ){
+ int nCmp = MIN(nTerm, pCsr->nLeTerm);
+ int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
+ if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){
+ pCsr->bEof = 1;
+ }
+ }
+
+ sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
+ }
+ return rc;
+}
+
+static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
+ int eDetail = pCsr->pConfig->eDetail;
+ int rc = SQLITE_OK;
+ Fts5IndexIter *pIter = pCsr->pIter;
+ i64 *pp = &pCsr->iInstPos;
+ int *po = &pCsr->iInstOff;
+
+ while( eDetail==FTS5_DETAIL_NONE
+ || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp)
+ ){
+ pCsr->iInstPos = 0;
+ pCsr->iInstOff = 0;
+
+ rc = sqlite3Fts5IterNextScan(pCsr->pIter);
+ if( rc==SQLITE_OK ){
+ rc = fts5VocabInstanceNewTerm(pCsr);
+ if( eDetail==FTS5_DETAIL_NONE ) break;
+ }
+ if( rc ){
+ pCsr->bEof = 1;
+ break;
+ }
+ }
+
+ return rc;
+}
/*
** Advance the cursor to the next row in the table.
@@ -204063,13 +204932,17 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
pCsr->rowid++;
+ if( pTab->eType==FTS5_VOCAB_INSTANCE ){
+ return fts5VocabInstanceNext(pCsr);
+ }
+
if( pTab->eType==FTS5_VOCAB_COL ){
for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
if( pCsr->aDoc[pCsr->iCol] ) break;
}
}
- if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){
+ if( pTab->eType!=FTS5_VOCAB_COL || pCsr->iCol>=nCol ){
if( sqlite3Fts5IterEof(pCsr->pIter) ){
pCsr->bEof = 1;
}else{
@@ -204093,22 +204966,26 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
while( rc==SQLITE_OK ){
+ int eDetail = pCsr->pConfig->eDetail;
const u8 *pPos; int nPos; /* Position list */
i64 iPos = 0; /* 64-bit position read from poslist */
int iOff = 0; /* Current offset within position list */
pPos = pCsr->pIter->pData;
nPos = pCsr->pIter->nData;
- switch( pCsr->pConfig->eDetail ){
- case FTS5_DETAIL_FULL:
- pPos = pCsr->pIter->pData;
- nPos = pCsr->pIter->nData;
- if( pTab->eType==FTS5_VOCAB_ROW ){
+
+ switch( pTab->eType ){
+ case FTS5_VOCAB_ROW:
+ if( eDetail==FTS5_DETAIL_FULL ){
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
pCsr->aCnt[0]++;
}
- pCsr->aDoc[0]++;
- }else{
+ }
+ pCsr->aDoc[0]++;
+ break;
+
+ case FTS5_VOCAB_COL:
+ if( eDetail==FTS5_DETAIL_FULL ){
int iCol = -1;
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
int ii = FTS5_POS2COLUMN(iPos);
@@ -204122,13 +204999,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
iCol = ii;
}
}
- }
- break;
-
- case FTS5_DETAIL_COLUMNS:
- if( pTab->eType==FTS5_VOCAB_ROW ){
- pCsr->aDoc[0]++;
- }else{
+ }else if( eDetail==FTS5_DETAIL_COLUMNS ){
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){
assert_nc( iPos>=0 && iPos<nCol );
if( iPos>=nCol ){
@@ -204137,18 +205008,21 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
}
pCsr->aDoc[iPos]++;
}
+ }else{
+ assert( eDetail==FTS5_DETAIL_NONE );
+ pCsr->aDoc[0]++;
}
break;
default:
- assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE );
- pCsr->aDoc[0]++;
+ assert( pTab->eType==FTS5_VOCAB_INSTANCE );
break;
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IterNextScan(pCsr->pIter);
}
+ if( pTab->eType==FTS5_VOCAB_INSTANCE ) break;
if( rc==SQLITE_OK ){
zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
@@ -204178,7 +205052,9 @@ static int fts5VocabFilterMethod(
int nUnused, /* Number of elements in apVal */
sqlite3_value **apVal /* Arguments for the indexing scheme */
){
+ Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
+ int eType = pTab->eType;
int rc = SQLITE_OK;
int iVal = 0;
@@ -204218,11 +205094,16 @@ static int fts5VocabFilterMethod(
}
}
-
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
}
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){
+ rc = fts5VocabInstanceNewTerm(pCsr);
+ }
+ if( rc==SQLITE_OK
+ && !pCsr->bEof
+ && (eType!=FTS5_VOCAB_INSTANCE || pCsr->pConfig->eDetail!=FTS5_DETAIL_NONE)
+ ){
rc = fts5VocabNextMethod(pCursor);
}
@@ -204264,13 +205145,41 @@ static int fts5VocabColumnMethod(
}else{
iVal = pCsr->aCnt[pCsr->iCol];
}
- }else{
+ }else if( eType==FTS5_VOCAB_ROW ){
assert( iCol==1 || iCol==2 );
if( iCol==1 ){
iVal = pCsr->aDoc[0];
}else{
iVal = pCsr->aCnt[0];
}
+ }else{
+ assert( eType==FTS5_VOCAB_INSTANCE );
+ switch( iCol ){
+ case 1:
+ sqlite3_result_int64(pCtx, pCsr->pIter->iRowid);
+ break;
+ case 2: {
+ int ii = -1;
+ if( eDetail==FTS5_DETAIL_FULL ){
+ ii = FTS5_POS2COLUMN(pCsr->iInstPos);
+ }else if( eDetail==FTS5_DETAIL_COLUMNS ){
+ ii = (int)pCsr->iInstPos;
+ }
+ if( ii>=0 && ii<pCsr->pConfig->nCol ){
+ const char *z = pCsr->pConfig->azCol[ii];
+ sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
+ }
+ break;
+ }
+ default: {
+ assert( iCol==3 );
+ if( eDetail==FTS5_DETAIL_FULL ){
+ int ii = FTS5_POS2OFFSET(pCsr->iInstPos);
+ sqlite3_result_int(pCtx, ii);
+ }
+ break;
+ }
+ }
}
if( iVal>0 ) sqlite3_result_int64(pCtx, iVal);
@@ -204630,3 +205539,10 @@ SQLITE_API int sqlite3_stmt_init(
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
/************** End of stmt.c ************************************************/
+#if __LINE__!=205536
+#undef SQLITE_SOURCE_ID
+#define SQLITE_SOURCE_ID "2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de4alt2"
+#endif
+/* Return the source-id for this library */
+SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
+/************************** End of sqlite3.c ******************************/
diff --git a/third_party/sqlite/amalgamation/sqlite3.h b/third_party/sqlite/amalgamation/sqlite3.h
index 0aa60a8..199a136 100644
--- a/third_party/sqlite/amalgamation/sqlite3.h
+++ b/third_party/sqlite/amalgamation/sqlite3.h
@@ -115,15 +115,17 @@ extern "C" {
** a string which identifies a particular check-in of SQLite
** within its configuration management system. ^The SQLITE_SOURCE_ID
** string contains the date and time of the check-in (UTC) and a SHA1
-** or SHA3-256 hash of the entire source tree.
+** or SHA3-256 hash of the entire source tree. If the source code has
+** been edited in any way since it was last checked in, then the last
+** four hexadecimal digits of the hash may be modified.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.20.0"
-#define SQLITE_VERSION_NUMBER 3020000
-#define SQLITE_SOURCE_ID "2017-07-19 19:48:40 0a5e1c04d9d07bb7fd6546a9ddac1bf42b19ea19c2b79570aea6cd4226887a27"
+#define SQLITE_VERSION "3.21.0"
+#define SQLITE_VERSION_NUMBER 3021000
+#define SQLITE_SOURCE_ID "2017-10-24 18:55:49 1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de4alt1"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -139,7 +141,7 @@ extern "C" {
**
** <blockquote><pre>
** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
-** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
+** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
** </pre></blockquote>)^
**
@@ -149,9 +151,11 @@ 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
+** [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.
+** [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].)^
**
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
@@ -432,7 +436,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
-#define SQLITE_EMPTY 16 /* Not used */
+#define SQLITE_EMPTY 16 /* Internal use only */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
@@ -494,6 +498,9 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
+#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_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
@@ -580,6 +587,11 @@ SQLITE_API int sqlite3_exec(
** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on
** read-only media and cannot be changed even by processes with
** elevated privileges.
+**
+** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
+** filesystem supports doing multiple write operations atomically when those
+** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
+** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -595,6 +607,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
+#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
/*
** CAPI3REF: File Locking Levels
@@ -729,6 +742,7 @@ struct sqlite3_file {
** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
** <li> [SQLITE_IOCAP_IMMUTABLE]
+** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
** </ul>
**
** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -1012,6 +1026,40 @@ struct sqlite3_io_methods {
** 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.
+**
+** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
+** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
+** the file descriptor is placed in "batch write mode", which
+** means all subsequent write operations will be deferred and done
+** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems
+** that do not support batch atomic writes will return SQLITE_NOTFOUND.
+** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
+** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
+** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
+** no VFS interface calls on the same [sqlite3_file] file descriptor
+** except for calls to the xWrite method and the xFileControl method
+** with [SQLITE_FCNTL_SIZE_HINT].
+**
+** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
+** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
+** 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.
+** ^Regardless of whether or not it is successful, this file control takes
+** the file descriptor out of batch write mode so that all subsequent
+** write operations are independent.
+** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
+** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
+**
+** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
+** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
+** 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.
+** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
+** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1043,6 +1091,9 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_JOURNAL_POINTER 28
#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
#define SQLITE_FCNTL_PDB 30
+#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31
+#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32
+#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1613,6 +1664,16 @@ struct sqlite3_mem_methods {
** routines with a wrapper that simulations memory allocation failure or
** tracks memory usage, for example. </dd>
**
+** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt>
+** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of
+** type int, interpreted as a boolean, which if true provides a hint to
+** SQLite that it should avoid large memory allocations if possible.
+** SQLite will run faster if it is free to make large memory allocations,
+** but some application might prefer to run slower in exchange for
+** guarantees about memory fragmentation that are possible if large
+** allocations are avoided. This hint is normally off.
+** </dd>
+**
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
** interpreted as a boolean, which enables or disables the collection of
@@ -1630,25 +1691,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
-** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
-** that SQLite can use for scratch memory. ^(There are three arguments
-** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte
-** aligned memory buffer from which the scratch allocations will be
-** drawn, the size of each scratch allocation (sz),
-** and the maximum number of scratch allocations (N).)^
-** The first argument must be a pointer to an 8-byte aligned buffer
-** of at least sz*N bytes of memory.
-** ^SQLite will not use more than one scratch buffers per thread.
-** ^SQLite will never request a scratch buffer that is more than 6
-** times the database page size.
-** ^If SQLite needs needs additional
-** scratch memory beyond what is provided by this configuration option, then
-** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
-** ^When the application provides any amount of scratch memory using
-** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
-** [sqlite3_malloc|heap allocations].
-** This can help [Robson proof|prevent memory allocation failures] due to heap
-** fragmentation in low-memory embedded systems.
+** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
@@ -1684,8 +1727,7 @@ struct sqlite3_mem_methods {
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
** <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_SCRATCH] and
-** [SQLITE_CONFIG_PAGECACHE].
+** beyond those provided for by [SQLITE_CONFIG_PAGECACHE].
** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
** [SQLITE_ERROR] if invoked otherwise.
@@ -1878,7 +1920,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
@@ -1899,6 +1941,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */
+#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -3099,10 +3142,10 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** ^If [URI filename] interpretation is enabled, and the filename argument
** begins with "file:", then the filename is interpreted as a URI. ^URI
** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
-** set in the fourth argument to sqlite3_open_v2(), or if it has
+** set in the third argument to sqlite3_open_v2(), or if it has
** been enabled globally using the [SQLITE_CONFIG_URI] option with the
** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
-** As of SQLite version 3.7.7, URI filename interpretation is turned off
+** URI filename interpretation is turned off
** by default, but future releases of SQLite might enable URI filename
** interpretation by default. See "[URI filenames]" for additional
** information.
@@ -3776,8 +3819,9 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
** implementation of [application-defined SQL functions] are protected.
** ^The sqlite3_value object returned by
** [sqlite3_column_value()] is unprotected.
-** Unprotected sqlite3_value objects may only be used with
-** [sqlite3_result_value()] and [sqlite3_bind_value()].
+** Unprotected sqlite3_value objects may only be used as arguments
+** to [sqlite3_result_value()], [sqlite3_bind_value()], and
+** [sqlite3_value_dup()].
** The [sqlite3_value_blob | sqlite3_value_type()] family of
** interfaces require protected sqlite3_value objects.
*/
@@ -6200,15 +6244,20 @@ struct sqlite3_index_info {
** 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_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
/*
** CAPI3REF: Register A Virtual Table Implementation
@@ -6960,7 +7009,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_RESERVE 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
+#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
@@ -7019,8 +7068,7 @@ SQLITE_API int sqlite3_status64(
** <dd>This parameter is the current amount of memory checked out
** using [sqlite3_malloc()], either directly or indirectly. The
** figure includes calls made to [sqlite3_malloc()] by the application
-** and internal memory usage by the SQLite library. Scratch memory
-** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache
+** and internal memory usage by the SQLite library. Auxiliary page-cache
** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in
** this parameter. The amount returned is the sum of the allocation
** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
@@ -7058,29 +7106,14 @@ SQLITE_API int sqlite3_status64(
** *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>
-** <dd>This parameter returns the number of allocations used out of the
-** [scratch memory allocator] configured using
-** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not
-** in bytes. Since a single thread may only have one scratch allocation
-** outstanding at time, this parameter also reports the number of threads
-** using scratch memory at the same time.</dd>)^
+** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
+** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
-** <dd>This parameter returns the number of bytes of scratch memory
-** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
-** buffer and where forced to overflow to [sqlite3_malloc()]. The values
-** returned include overflows because the requested allocation was too
-** larger (that is, because the requested allocation was larger than the
-** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer
-** slots were available.
-** </dd>)^
-**
-** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
-** <dd>This parameter records the largest memory allocation request
-** handed to [scratch memory allocator]. Only the value returned in the
-** *pHighwater parameter to [sqlite3_status()] is of interest.
-** The value written into the *pCurrent parameter is undefined.</dd>)^
+** <dd>No longer used.</dd>
+**
+** [[SQLITE_STATUS_SCRATCH_SIZE]] <dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
+** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
** <dd>The *pHighwater parameter records the deepest parser stack.
@@ -7093,12 +7126,12 @@ SQLITE_API int sqlite3_status64(
#define SQLITE_STATUS_MEMORY_USED 0
#define SQLITE_STATUS_PAGECACHE_USED 1
#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2
-#define SQLITE_STATUS_SCRATCH_USED 3
-#define SQLITE_STATUS_SCRATCH_OVERFLOW 4
+#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */
+#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */
#define SQLITE_STATUS_MALLOC_SIZE 5
#define SQLITE_STATUS_PARSER_STACK 6
#define SQLITE_STATUS_PAGECACHE_SIZE 7
-#define SQLITE_STATUS_SCRATCH_SIZE 8
+#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */
#define SQLITE_STATUS_MALLOC_COUNT 9
/*
@@ -9218,8 +9251,8 @@ SQLITE_API int sqlite3session_diff(
*/
SQLITE_API int sqlite3session_patchset(
sqlite3_session *pSession, /* Session object */
- int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
- void **ppPatchset /* OUT: Buffer containing changeset */
+ int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */
+ void **ppPatchset /* OUT: Buffer containing patchset */
);
/*
@@ -9986,12 +10019,12 @@ SQLITE_API int sqlite3changeset_apply(
**
** <table border=1 style="margin-left:8ex;margin-right:8ex">
** <tr><th>Streaming function<th>Non-streaming equivalent</th>
-** <tr><td>sqlite3changeset_apply_str<td>[sqlite3changeset_apply]
-** <tr><td>sqlite3changeset_concat_str<td>[sqlite3changeset_concat]
-** <tr><td>sqlite3changeset_invert_str<td>[sqlite3changeset_invert]
-** <tr><td>sqlite3changeset_start_str<td>[sqlite3changeset_start]
-** <tr><td>sqlite3session_changeset_str<td>[sqlite3session_changeset]
-** <tr><td>sqlite3session_patchset_str<td>[sqlite3session_patchset]
+** <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply]
+** <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
diff --git a/third_party/sqlite/google_generate_amalgamation.sh b/third_party/sqlite/google_generate_amalgamation.sh
index cf21cd1..0a1c0fc 100755
--- a/third_party/sqlite/google_generate_amalgamation.sh
+++ b/third_party/sqlite/google_generate_amalgamation.sh
@@ -9,7 +9,7 @@ cd src
mkdir bld
cd bld
../configure
-FILES="sqlite3.h sqlite3.c"
+FILES="shell.c sqlite3.h sqlite3.c"
OPTS=""
make "OPTS=$OPTS" $FILES
cp -f $FILES ../../amalgamation
diff --git a/third_party/sqlite/patches/0001-test-SQLite-tests-compiling-on-Linux.patch b/third_party/sqlite/patches/0001-test-SQLite-tests-compiling-on-Linux.patch
index b9f982b..e668ae9 100644
--- a/third_party/sqlite/patches/0001-test-SQLite-tests-compiling-on-Linux.patch
+++ b/third_party/sqlite/patches/0001-test-SQLite-tests-compiling-on-Linux.patch
@@ -1,4 +1,4 @@
-From a9d3b5dc29050f562174939d7154a26ea66ac779 Mon Sep 17 00:00:00 2001
+From e6a52a13daabf722ed5bee436af214babae113c1 Mon Sep 17 00:00:00 2001
From: Scott Hess <shess@chromium.org>
Date: Fri, 16 Jan 2015 10:24:30 -0800
Subject: [PATCH 01/10] [test] SQLite tests compiling on Linux.
@@ -18,7 +18,7 @@ index b838b844a312..62d029430803 100644
#
-TOP = ../sqlite
+TOP = ..
-
+
#### C Compiler and options for use in building executables that
# will run on the platform that is doing the build.
@@ -32,19 +32,19 @@ USLEEP = -DHAVE_USLEEP=1
@@ -29,7 +29,7 @@ index b838b844a312..62d029430803 100644
-THREADSAFE = -DTHREADSAFE=0
+THREADSAFE = -DTHREADSAFE=1
+#THREADSAFE = -DTHREADSAFE=0
-
+
#### Specify any extra linker options needed to make the library
# thread safe
#
@@ -37,13 +37,13 @@ index b838b844a312..62d029430803 100644
-THREADLIB =
+THREADLIB = -lpthread
+#THREADLIB =
-
+
#### Specify any extra libraries needed to access required functions.
#
#TLIBS = -lrt # fdatasync on Solaris 8
-TLIBS =
+TLIBS = -ldl
-
+
#### Leave SQLITE_DEBUG undefined for maximum speed. Use SQLITE_DEBUG=1
# to check for memory leaks. Use SQLITE_DEBUG=2 to print a log of all
@@ -58,7 +58,24 @@ TLIBS =
@@ -69,7 +69,7 @@ index b838b844a312..62d029430803 100644
+
+# TODO(shess) I can't see why I need this setting.
+OPTS += -DOS_UNIX=1
-
+
#### The suffix to add to executable files. ".exe" for windows.
# Nothing for unix.
@@ -70,7 +87,7 @@ EXE =
@@ -82,7 +82,7 @@ index b838b844a312..62d029430803 100644
#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
#TCC = /opt/mingw/bin/i386-mingw32-gcc -O6
@@ -91,16 +108,16 @@ SHPREFIX = lib
-
+
#### Extra compiler options needed for programs that use the TCL library.
#
-#TCL_FLAGS =
@@ -92,7 +92,7 @@ index b838b844a312..62d029430803 100644
+#TCL_FLAGS = -I/home/drh/tcltk/8.5linux
#TCL_FLAGS = -I/home/drh/tcltk/8.5win -DSTATIC_BUILD=1
#TCL_FLAGS = -I/home/drh/tcltk/8.3hpux
-
+
#### Linker options needed to link against the TCL library.
#
-#LIBTCL = -ltcl -lm -ldl
@@ -101,20 +101,19 @@ index b838b844a312..62d029430803 100644
+#LIBTCL = /home/drh/tcltk/8.5linux/libtcl8.5g.a -lm -ldl
#LIBTCL = /home/drh/tcltk/8.5win/libtcl85s.a -lmsvcrt
#LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc
-
+
diff --git a/third_party/sqlite/src/main.mk b/third_party/sqlite/src/main.mk
-index 62ba293d5b9d..32c394e7812d 100644
+index d45f8b8a4daf..be694f0d5586 100644
--- a/third_party/sqlite/src/main.mk
+++ b/third_party/sqlite/src/main.mk
-@@ -766,7 +766,7 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl
- echo "; return zMainloop; }" >> $@
-
+@@ -784,7 +784,7 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $
+ tclsh $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
+
sqlite3_analyzer$(EXE): sqlite3_analyzer.c
- $(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB)
+ $(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS) $(THREADLIB)
-
+
dbdump$(EXE): $(TOP)/ext/misc/dbdump.c sqlite3.o
$(TCCX) -DDBDUMP_STANDALONE -o dbdump$(EXE) \
---
-2.13.1.518.g3df882009-goog
-
+--
+2.14.0
diff --git a/third_party/sqlite/patches/0002-Use-seperate-page-cache-pools-for-each-sqlite-connec.patch b/third_party/sqlite/patches/0002-Use-seperate-page-cache-pools-for-each-sqlite-connec.patch
index 3a98544..d6417fd 100644
--- a/third_party/sqlite/patches/0002-Use-seperate-page-cache-pools-for-each-sqlite-connec.patch
+++ b/third_party/sqlite/patches/0002-Use-seperate-page-cache-pools-for-each-sqlite-connec.patch
@@ -1,4 +1,4 @@
-From 0189f2ce45d8c2ed45e5321361cd7de21ea4432e Mon Sep 17 00:00:00 2001
+From a5bfa4afd458372a73efed9b191a02c7b7c000c5 Mon Sep 17 00:00:00 2001
From: rmcilroy <rmcilroy@chromium.org>
Date: Thu, 20 Jun 2013 22:50:12 +0000
Subject: [PATCH 02/10] Use seperate page-cache pools for each sqlite
@@ -16,7 +16,7 @@ Original review URL: https://chromiumcodereview.appspot.com/17413004
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/third_party/sqlite/src/src/pcache1.c b/third_party/sqlite/src/src/pcache1.c
-index 885b8b11fcf7..4b09e9805e82 100644
+index 2692bd6ac9d3..c93294a9df71 100644
--- a/third_party/sqlite/src/src/pcache1.c
+++ b/third_party/sqlite/src/src/pcache1.c
@@ -689,6 +689,8 @@ static int pcache1Init(void *NotUsed){
@@ -39,6 +39,5 @@ index 885b8b11fcf7..4b09e9805e82 100644
pcache1.separateCache = 0;
#elif SQLITE_THREADSAFE
pcache1.separateCache = sqlite3GlobalConfig.pPage==0
---
-2.13.1.518.g3df882009-goog
-
+--
+2.14.0
diff --git a/third_party/sqlite/patches/0003-Modify-default-VFS-to-support-WebDatabase.patch b/third_party/sqlite/patches/0003-Modify-default-VFS-to-support-WebDatabase.patch
index 2c6ea2d..3a14846 100644
--- a/third_party/sqlite/patches/0003-Modify-default-VFS-to-support-WebDatabase.patch
+++ b/third_party/sqlite/patches/0003-Modify-default-VFS-to-support-WebDatabase.patch
@@ -1,4 +1,4 @@
-From 718473c4f2c41afdd60132f3cf97d0567e8a3aa4 Mon Sep 17 00:00:00 2001
+From 3b4029bed436558ae745630e970b0f6d8040fb54 Mon Sep 17 00:00:00 2001
From: dumi <dumi@chromium.org>
Date: Mon, 20 Jul 2009 23:40:51 +0000
Subject: [PATCH 03/10] Modify default VFS to support WebDatabase.
@@ -17,16 +17,16 @@ https://codereview.chromium.org/384075
https://codereview.chromium.org/377039
[Possibly not a complete list.]
---
- third_party/sqlite/src/src/os_unix.c | 49 ++++++++++++++++++++++++++++++++++
+ third_party/sqlite/src/src/os_unix.c | 50 ++++++++++++++++++++++++++++++++++
third_party/sqlite/src/src/os_win.c | 8 ++++++
third_party/sqlite/src/src/sqlite.h.in | 23 ++++++++++++++++
- 3 files changed, 80 insertions(+)
+ 3 files changed, 81 insertions(+)
diff --git a/third_party/sqlite/src/src/os_unix.c b/third_party/sqlite/src/src/os_unix.c
-index 8ab779a35288..44f6d67ee07f 100644
+index 1b7e5f344a69..6ed6f6a8fc98 100644
--- a/third_party/sqlite/src/src/os_unix.c
+++ b/third_party/sqlite/src/src/os_unix.c
-@@ -1346,6 +1346,12 @@ static int fileHasMoved(unixFile *pFile){
+@@ -1366,6 +1366,12 @@ static int fileHasMoved(unixFile *pFile){
return pFile->pInode!=0 && pFile->pId!=pFile->pInode->fileId.pId;
#else
struct stat buf;
@@ -39,10 +39,10 @@ index 8ab779a35288..44f6d67ee07f 100644
return pFile->pInode!=0 &&
(osStat(pFile->zPath, &buf)!=0
|| (u64)buf.st_ino!=pFile->pInode->fileId.ino);
-@@ -5639,6 +5645,44 @@ static int findCreateFileMode(
+@@ -5688,6 +5694,45 @@ static int findCreateFileMode(
return rc;
}
-
+
+/*
+** Initialize |unixFile| internals of |file| on behalf of chromiumOpen() in
+** WebDatabase SQLiteFileSystemPosix.cpp. Function is a subset of unixOpen(),
@@ -63,20 +63,21 @@ index 8ab779a35288..44f6d67ee07f 100644
+ memset(p, 0, sizeof(unixFile));
+
+ /* osStat() will not work in the sandbox, so findReusableFd() will always
-+ ** fail, so directly include the failure-case setup then initialize pUnused.
++ ** fail, so directly include the failure-case setup then initialize
++ ** pPreallocatedUnused.
+ */
+ if( eType==SQLITE_OPEN_MAIN_DB ){
-+ p->pUnused = sqlite3_malloc(sizeof(*p->pUnused));
-+ if (!p->pUnused) {
++ p->pPreallocatedUnused = sqlite3_malloc(sizeof(*p->pPreallocatedUnused));
++ if (!p->pPreallocatedUnused) {
+ return SQLITE_NOMEM_BKPT;
+ }
-+ p->pUnused->fd = fd;
-+ p->pUnused->flags = flags;
++ p->pPreallocatedUnused->fd = fd;
++ p->pPreallocatedUnused->flags = flags;
+ }
+
+ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
+ if( rc!=SQLITE_OK ){
-+ sqlite3_free(p->pUnused);
++ sqlite3_free(p->pPreallocatedUnused);
+ }
+ return rc;
+}
@@ -84,15 +85,15 @@ index 8ab779a35288..44f6d67ee07f 100644
/*
** Open the file zPath.
**
-@@ -5740,6 +5784,7 @@ static int unixOpen(
+@@ -5789,6 +5834,7 @@ static int unixOpen(
sqlite3_randomness(0,0);
}
-
+
+ /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
memset(p, 0, sizeof(unixFile));
-
+
if( eType==SQLITE_OPEN_MAIN_DB ){
-@@ -5748,6 +5793,7 @@ static int unixOpen(
+@@ -5797,6 +5843,7 @@ static int unixOpen(
if( pUnused ){
fd = pUnused->fd;
}else{
@@ -100,35 +101,35 @@ index 8ab779a35288..44f6d67ee07f 100644
pUnused = sqlite3_malloc64(sizeof(*pUnused));
if( !pUnused ){
return SQLITE_NOMEM_BKPT;
-@@ -5825,6 +5871,7 @@ static int unixOpen(
+@@ -5874,6 +5921,7 @@ static int unixOpen(
}
-
- if( p->pUnused ){
+
+ if( p->pPreallocatedUnused ){
+ /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
- p->pUnused->fd = fd;
- p->pUnused->flags = flags;
- }
-@@ -5903,10 +5950,12 @@ static int unixOpen(
+ p->pPreallocatedUnused->fd = fd;
+ p->pPreallocatedUnused->flags = flags;
}
- #endif
-
+@@ -5955,10 +6003,12 @@ static int unixOpen(
+ assert( zPath==0 || zPath[0]=='/'
+ || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
+ );
+ /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
-
+
open_finished:
if( rc!=SQLITE_OK ){
+ /* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
- sqlite3_free(p->pUnused);
+ sqlite3_free(p->pPreallocatedUnused);
}
return rc;
diff --git a/third_party/sqlite/src/src/os_win.c b/third_party/sqlite/src/src/os_win.c
-index a87d7d09256d..1d9abf0a8f35 100644
+index 245a86045bae..eeb2c149800d 100644
--- a/third_party/sqlite/src/src/os_win.c
+++ b/third_party/sqlite/src/src/os_win.c
-@@ -5998,4 +5998,12 @@ int sqlite3_os_end(void){
+@@ -6026,4 +6026,12 @@ int sqlite3_os_end(void){
return SQLITE_OK;
}
-
+
+CHROMIUM_SQLITE_API
+void chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle) {
+ winFile* winSQLite3File = (winFile*)file;
@@ -139,13 +140,13 @@ index a87d7d09256d..1d9abf0a8f35 100644
+
#endif /* SQLITE_OS_WIN */
diff --git a/third_party/sqlite/src/src/sqlite.h.in b/third_party/sqlite/src/src/sqlite.h.in
-index 025fa5dadc40..2503d76c8f27 100644
+index 64685fef4569..877e79f74af2 100644
--- a/third_party/sqlite/src/src/sqlite.h.in
+++ b/third_party/sqlite/src/src/sqlite.h.in
-@@ -7918,6 +7918,29 @@ int sqlite3_strnicmp(const char *, const char *, int);
+@@ -7954,6 +7954,29 @@ int sqlite3_strnicmp(const char *, const char *, int);
*/
int sqlite3_strglob(const char *zGlob, const char *zStr);
-
+
+/* Begin WebDatabase patch for Chromium */
+/* Expose some SQLite internals for the WebDatabase vfs.
+** DO NOT EXTEND THE USE OF THIS.
@@ -172,6 +173,5 @@ index 025fa5dadc40..2503d76c8f27 100644
/*
** CAPI3REF: String LIKE Matching
*
---
-2.13.1.518.g3df882009-goog
-
+--
+2.14.0
diff --git a/third_party/sqlite/patches/0004-Virtual-table-supporting-recovery-of-corrupted-datab.patch b/third_party/sqlite/patches/0004-Virtual-table-supporting-recovery-of-corrupted-datab.patch
index 3b60cd8..3c44adc 100644
--- a/third_party/sqlite/patches/0004-Virtual-table-supporting-recovery-of-corrupted-datab.patch
+++ b/third_party/sqlite/patches/0004-Virtual-table-supporting-recovery-of-corrupted-datab.patch
@@ -1,4 +1,4 @@
-From 116d95a1309084e8ef963e8735d426e74d595b99 Mon Sep 17 00:00:00 2001
+From 86758183a3ed8211f997c10f47582847686eaa95 Mon Sep 17 00:00:00 2001
From: Scott Hess <shess@chromium.org>
Date: Sat, 20 Jul 2013 11:42:21 -0700
Subject: [PATCH 04/10] Virtual table supporting recovery of corrupted
@@ -34,19 +34,19 @@ third_party/sqlite/src/src/{recover,recover-alt}.c .
create mode 100644 third_party/sqlite/src/test/recover2.test
diff --git a/third_party/sqlite/src/main.mk b/third_party/sqlite/src/main.mk
-index 32c394e7812d..7e39a3d92c35 100644
+index be694f0d5586..e645794c2325 100644
--- a/third_party/sqlite/src/main.mk
+++ b/third_party/sqlite/src/main.mk
-@@ -76,6 +76,8 @@ LIBOBJ+= vdbe.o parse.o \
+@@ -77,6 +77,8 @@ LIBOBJ+= vdbe.o parse.o \
vdbetrace.o wal.o walker.o where.o wherecode.o whereexpr.o \
utf.o vtab.o
-
+
+LIBOBJ += recover.o recover_varint.o
+
LIBOBJ += sqlite3session.o
-
+
# All of the source code files.
-@@ -373,6 +375,8 @@ TESTSRC2 = \
+@@ -380,6 +382,8 @@ TESTSRC2 = \
$(TOP)/src/prepare.c \
$(TOP)/src/printf.c \
$(TOP)/src/random.c \
@@ -55,22 +55,22 @@ index 32c394e7812d..7e39a3d92c35 100644
$(TOP)/src/pcache.c \
$(TOP)/src/pcache1.c \
$(TOP)/src/select.c \
-@@ -779,6 +783,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
- TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
- TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
+@@ -799,6 +803,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
+ TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
+ TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
+TESTFIXTURE_FLAGS += -DDEFAULT_ENABLE_RECOVER=1
-
+
testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
- $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
+ $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
diff --git a/third_party/sqlite/src/src/main.c b/third_party/sqlite/src/src/main.c
-index b706a0e49cf0..0b8c18d90620 100644
+index 8b6aac07a5a2..0709b3a34330 100644
--- a/third_party/sqlite/src/src/main.c
+++ b/third_party/sqlite/src/src/main.c
-@@ -3041,6 +3041,14 @@ static int openDatabase(
+@@ -3042,6 +3042,14 @@ static int openDatabase(
}
#endif
-
+
+#ifdef DEFAULT_ENABLE_RECOVER
+ /* Initialize recover virtual table for testing. */
+ extern int recoverVtableInit(sqlite3 *db);
@@ -3900,6 +3900,5 @@ index 000000000000..8aa4e049a010
+} [list 4 1024 1 text [string length $substr] $substr]
+
+finish_test
---
-2.13.1.518.g3df882009-goog
-
+--
+2.14.0
diff --git a/third_party/sqlite/patches/0005-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch b/third_party/sqlite/patches/0005-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch
index d12638a..9c7f6df 100644
--- a/third_party/sqlite/patches/0005-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch
+++ b/third_party/sqlite/patches/0005-Custom-shell.c-helpers-to-load-Chromium-s-ICU-data.patch
@@ -1,4 +1,4 @@
-From 7be8f980d0e23ee4b336fdcfc25152c650a0e65a Mon Sep 17 00:00:00 2001
+From 964180d41d6d75cacf27c4764dca353b82ceb784 Mon Sep 17 00:00:00 2001
From: "tc@google.com" <tc@google.com>
Date: Tue, 6 Jan 2009 22:39:41 +0000
Subject: [PATCH 05/10] Custom shell.c helpers to load Chromium's ICU data.
@@ -10,7 +10,7 @@ Original review URL: https://codereview.chromium.org/42250
---
third_party/sqlite/src/Makefile.linux-gcc | 7 ++++++
third_party/sqlite/src/main.mk | 2 +-
- third_party/sqlite/src/src/shell.c | 10 +++++++++
+ third_party/sqlite/src/src/shell.c.in | 10 +++++++++
third_party/sqlite/src/src/shell_icu_linux.c | 27 +++++++++++++++++++++++
third_party/sqlite/src/src/shell_icu_win.c | 32 ++++++++++++++++++++++++++++
5 files changed, 77 insertions(+), 1 deletion(-)
@@ -24,7 +24,7 @@ index 62d029430803..a37d41a0099d 100644
@@ -77,6 +77,13 @@ OPTS += -DSQLITE_MEMDEBUG=1
# TODO(shess) I can't see why I need this setting.
OPTS += -DOS_UNIX=1
-
+
+# Support for loading Chromium ICU data in sqlite3.
+ifeq ($(shell uname -s),Darwin)
+SHELL_ICU =
@@ -36,26 +36,26 @@ index 62d029430803..a37d41a0099d 100644
# Nothing for unix.
#
diff --git a/third_party/sqlite/src/main.mk b/third_party/sqlite/src/main.mk
-index 7e39a3d92c35..908cf510c5b3 100644
+index e645794c2325..5c34a8d9b53e 100644
--- a/third_party/sqlite/src/main.mk
+++ b/third_party/sqlite/src/main.mk
-@@ -501,7 +501,7 @@ libsqlite3.a: $(LIBOBJ)
-
- sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h
+@@ -510,7 +510,7 @@ libsqlite3.a: $(LIBOBJ)
+
+ sqlite3$(EXE): shell.c libsqlite3.a sqlite3.h
$(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \
-- $(TOP)/src/shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
-+ $(TOP)/src/shell.c $(SHELL_ICU) libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
-
+- shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
++ shell.c $(SHELL_ICU) libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
+
sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h
$(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \
-diff --git a/third_party/sqlite/src/src/shell.c b/third_party/sqlite/src/src/shell.c
-index fa51056c42cc..33f41f694e41 100644
---- a/third_party/sqlite/src/src/shell.c
-+++ b/third_party/sqlite/src/src/shell.c
-@@ -8067,6 +8067,16 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
+diff --git a/third_party/sqlite/src/src/shell.c.in b/third_party/sqlite/src/src/shell.c.in
+index 8f5ed59e9304..a500a19ca7df 100644
+--- a/third_party/sqlite/src/src/shell.c.in
++++ b/third_party/sqlite/src/src/shell.c.in
+@@ -6703,6 +6703,16 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}
#endif
-
+
+ /* Begin evanm patch. */
+#if !defined(__APPLE__)
+ extern int sqlite_shell_init_icu();
@@ -140,6 +140,5 @@ index 000000000000..67ebbf4fbdb4
+
+ return 1;
+}
---
-2.13.1.518.g3df882009-goog
-
+--
+2.14.0
diff --git a/third_party/sqlite/patches/0006-fts3-Disable-fts3_tokenizer-and-fts4.patch b/third_party/sqlite/patches/0006-fts3-Disable-fts3_tokenizer-and-fts4.patch
index 543ce02..a3a532c 100644
--- a/third_party/sqlite/patches/0006-fts3-Disable-fts3_tokenizer-and-fts4.patch
+++ b/third_party/sqlite/patches/0006-fts3-Disable-fts3_tokenizer-and-fts4.patch
@@ -1,4 +1,4 @@
-From e249174e02172cdddc4b22662d092303b3814d10 Mon Sep 17 00:00:00 2001
+From 11549819a8c9f9ebc7cea2501c6939e497014524 Mon Sep 17 00:00:00 2001
From: Scott Hess <shess@chromium.org>
Date: Tue, 16 Dec 2014 13:02:27 -0800
Subject: [PATCH 06/10] [fts3] Disable fts3_tokenizer and fts4.
@@ -22,7 +22,7 @@ index 03a22f80f9ea..06c20756c85a 100644
** older data.
*/
+#define CHROMIUM_FTS3_CHANGES 1
-
+
#include "fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
@@ -3972,7 +3973,11 @@ int sqlite3Fts3Init(sqlite3 *db){
@@ -54,7 +54,6 @@ index 03a22f80f9ea..06c20756c85a 100644
+#endif
return rc;
}
-
---
-2.13.1.518.g3df882009-goog
+--
+2.14.0
diff --git a/third_party/sqlite/patches/0007-fts3-Interior-node-corruption-detection.patch b/third_party/sqlite/patches/0007-fts3-Interior-node-corruption-detection.patch
index 3c9ad4f..ad78991 100644
--- a/third_party/sqlite/patches/0007-fts3-Interior-node-corruption-detection.patch
+++ b/third_party/sqlite/patches/0007-fts3-Interior-node-corruption-detection.patch
@@ -1,4 +1,4 @@
-From e26dff5d8ad6e582d18bdd7dbc233e0cdd4b1034 Mon Sep 17 00:00:00 2001
+From 0eeedaeb8c90b61873e984cb005a9713bb659340 Mon Sep 17 00:00:00 2001
From: Scott Hess <shess@chromium.org>
Date: Thu, 26 May 2011 18:44:46 +0000
Subject: [PATCH 07/10] [fts3] Interior node corruption detection.
@@ -27,7 +27,7 @@ index 06c20756c85a..2d21c4fd6844 100644
@@ -1859,8 +1859,13 @@ static int fts3ScanInteriorNode(
isFirstTerm = 0;
zCsr += fts3GetVarint32(zCsr, &nSuffix);
-
+
- assert( nPrefix>=0 && nSuffix>=0 );
- if( &zCsr[nSuffix]>zEnd ){
+ /* NOTE(shess): Previous code checked for negative nPrefix and
@@ -40,6 +40,5 @@ index 06c20756c85a..2d21c4fd6844 100644
rc = FTS_CORRUPT_VTAB;
goto finish_scan;
}
---
-2.13.1.518.g3df882009-goog
-
+--
+2.14.0
diff --git a/third_party/sqlite/patches/0008-fts3-Fix-uninit-variable-in-fts3EvalDeferredPhrase.patch b/third_party/sqlite/patches/0008-fts3-Fix-uninit-variable-in-fts3EvalDeferredPhrase.patch
index f0d0674..e583fc1 100644
--- a/third_party/sqlite/patches/0008-fts3-Fix-uninit-variable-in-fts3EvalDeferredPhrase.patch
+++ b/third_party/sqlite/patches/0008-fts3-Fix-uninit-variable-in-fts3EvalDeferredPhrase.patch
@@ -1,4 +1,4 @@
-From 6bf4c55498680496d6e150d22219f7a980566ce6 Mon Sep 17 00:00:00 2001
+From a3b999263f36b0807ce4ead622e9ad8a536e641b Mon Sep 17 00:00:00 2001
From: Scott Hess <shess@chromium.org>
Date: Thu, 12 Feb 2015 15:01:26 -0800
Subject: [PATCH 08/10] [fts3] Fix uninit variable in fts3EvalDeferredPhrase.
@@ -19,7 +19,7 @@ index 2d21c4fd6844..a563dc788c77 100644
+++ b/third_party/sqlite/src/ext/fts3/fts3.c
@@ -4187,8 +4187,8 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
Fts3DeferredToken *pDeferred = pToken->pDeferred;
-
+
if( pDeferred ){
- char *pList;
- int nList;
@@ -27,7 +27,6 @@ index 2d21c4fd6844..a563dc788c77 100644
+ int nList = 0;
int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList);
if( rc!=SQLITE_OK ) return rc;
-
---
-2.13.1.518.g3df882009-goog
+--
+2.14.0
diff --git a/third_party/sqlite/patches/0009-Allow-auto-vacuum-to-work-with-chunks.patch b/third_party/sqlite/patches/0009-Allow-auto-vacuum-to-work-with-chunks.patch
new file mode 100644
index 0000000..04bf254
--- /dev/null
+++ b/third_party/sqlite/patches/0009-Allow-auto-vacuum-to-work-with-chunks.patch
@@ -0,0 +1,301 @@
+From e3f2de64eb622782bdad355e378b9733984c12f4 Mon Sep 17 00:00:00 2001
+From: Scott Hess <shess@chromium.org>
+Date: Thu, 2 Mar 2017 15:23:09 -0800
+Subject: [PATCH 09/10] Allow auto-vacuum to work with chunks.
+
+SQLITE_FCNTL_CHUNK_SIZE can advise the VFS to resize files in quantum
+amounts, to reduce fragmentation from tiny appends. This change allows
+a new PRAGMA auto_vacuum_slack_pages to provide auto_vacuum with a hint
+to only rearrange pages when an entire quantum can be released.
+
+When rebasing this patch, first ignore the conflicts in src/pragma.h,
+and fix all the other conflicts. Then run the commands below (in
+third_party/sqlite) to re-generate src/pragma.h.
+tclsh src/tool/mkpragmatab.tcl
+find src/ -type f -iname "*.h" -exec \
+ $GNU_SED --in-place 's/[[:space:]]\+$//' {} \+
+
+BUG=698010
+---
+ third_party/sqlite/src/src/btree.c | 56 ++++++++++++++++-
+ third_party/sqlite/src/src/btree.h | 2 +
+ third_party/sqlite/src/src/btreeInt.h | 1 +
+ third_party/sqlite/src/src/pragma.c | 21 +++++++
+ third_party/sqlite/src/src/pragma.h | 98 +++++++++++++++--------------
+ third_party/sqlite/src/tool/mkpragmatab.tcl | 4 ++
+ 6 files changed, 135 insertions(+), 47 deletions(-)
+
+diff --git a/third_party/sqlite/src/src/btree.c b/third_party/sqlite/src/src/btree.c
+index e62f3af10f52..e349eac4b01f 100644
+--- a/third_party/sqlite/src/src/btree.c
++++ b/third_party/sqlite/src/src/btree.c
+@@ -2943,6 +2943,46 @@ static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){
+ # define setDefaultSyncFlag(pBt,safety_level)
+ #endif
+
++/*
++** Change the 'auto-vacuum-slack-pages' property of the database. If auto vacuum
++** is enabled, this is the number of chunks of slack to allow before
++** automatically running an incremental vacuum.
++*/
++int sqlite3BtreeSetAutoVacuumSlackPages(Btree *p, int autoVacuumSlack){
++#ifdef SQLITE_OMIT_AUTOVACUUM
++ return SQLITE_READONLY;
++#else
++ BtShared *pBt = p->pBt;
++ int rc = SQLITE_OK;
++ u8 avs = (u8)autoVacuumSlack;
++ if( autoVacuumSlack>avs ){
++ avs = 0xFF;
++ }
++
++ sqlite3BtreeEnter(p);
++ pBt->autoVacuumSlack = avs;
++ sqlite3BtreeLeave(p);
++ return rc;
++#endif
++}
++
++/*
++** Return the value of the 'auto-vacuum-slack-pages' property.
++*/
++int sqlite3BtreeGetAutoVacuumSlackPages(Btree *p){
++#ifdef SQLITE_OMIT_AUTOVACUUM
++ return 0;
++#else
++ int rc = 0;
++ sqlite3BtreeEnter(p);
++ if( p->pBt->autoVacuum!=0 ){
++ rc = p->pBt->autoVacuumSlack;
++ }
++ sqlite3BtreeLeave(p);
++ return rc;
++#endif
++}
++
+ /*
+ ** Get a reference to pPage1 of the database file. This will
+ ** also acquire a readlock on that file.
+@@ -3772,13 +3812,27 @@ int sqlite3BtreeIncrVacuum(Btree *p){
+ */
+ static int autoVacuumCommit(BtShared *pBt){
+ int rc = SQLITE_OK;
++ int bShouldVacuum = pBt->autoVacuum && !pBt->incrVacuum;
+ Pager *pPager = pBt->pPager;
+ VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager); )
+
+ assert( sqlite3_mutex_held(pBt->mutex) );
+ invalidateAllOverflowCache(pBt);
+ assert(pBt->autoVacuum);
+- if( !pBt->incrVacuum ){
++ if( bShouldVacuum && pBt->autoVacuumSlack ){
++ Pgno nOrig; /* Database size before freeing */
++ Pgno nFree; /* Number of pages on the freelist initially */
++
++ nOrig = btreePagecount(pBt);
++ nFree = get4byte(&pBt->pPage1->aData[36]);
++ bShouldVacuum =
++ (nOrig-nFree-1)/pBt->autoVacuumSlack < (nOrig-1)/pBt->autoVacuumSlack;
++ /* TODO: When integrating this test with the following code, contrive to
++ ** trim to the integral chunk boundary, rather than trimming the entire free
++ ** list.
++ */
++ }
++ if( bShouldVacuum ){
+ Pgno nFin; /* Number of pages in database after autovacuuming */
+ Pgno nFree; /* Number of pages on the freelist initially */
+ Pgno iFree; /* The next page to be freed */
+diff --git a/third_party/sqlite/src/src/btree.h b/third_party/sqlite/src/src/btree.h
+index b348e9298461..3a0b008abadb 100644
+--- a/third_party/sqlite/src/src/btree.h
++++ b/third_party/sqlite/src/src/btree.h
+@@ -78,6 +78,8 @@ int sqlite3BtreeGetOptimalReserve(Btree*);
+ int sqlite3BtreeGetReserveNoMutex(Btree *p);
+ int sqlite3BtreeSetAutoVacuum(Btree *, int);
+ int sqlite3BtreeGetAutoVacuum(Btree *);
++int sqlite3BtreeSetAutoVacuumSlackPages(Btree *, int);
++int sqlite3BtreeGetAutoVacuumSlackPages(Btree *);
+ int sqlite3BtreeBeginTrans(Btree*,int);
+ int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
+ int sqlite3BtreeCommitPhaseTwo(Btree*, int);
+diff --git a/third_party/sqlite/src/src/btreeInt.h b/third_party/sqlite/src/src/btreeInt.h
+index 8b2a9af192bf..0694b31a78cc 100644
+--- a/third_party/sqlite/src/src/btreeInt.h
++++ b/third_party/sqlite/src/src/btreeInt.h
+@@ -412,6 +412,7 @@ struct BtShared {
+ u8 openFlags; /* Flags to sqlite3BtreeOpen() */
+ #ifndef SQLITE_OMIT_AUTOVACUUM
+ u8 autoVacuum; /* True if auto-vacuum is enabled */
++ u8 autoVacuumSlack; /* Optional pages of slack for auto-vacuum */
+ u8 incrVacuum; /* True if incr-vacuum is enabled */
+ u8 bDoTruncate; /* True to truncate db on commit */
+ #endif
+diff --git a/third_party/sqlite/src/src/pragma.c b/third_party/sqlite/src/src/pragma.c
+index c633429b7785..c1a2781b5549 100644
+--- a/third_party/sqlite/src/src/pragma.c
++++ b/third_party/sqlite/src/src/pragma.c
+@@ -756,6 +756,27 @@ void sqlite3Pragma(
+ }
+ #endif
+
++ /*
++ ** PRAGMA [schema.]auto_vacuum_slack_pages(N)
++ **
++ ** Control chunk size of auto-vacuum.
++ */
++#ifndef SQLITE_OMIT_AUTOVACUUM
++ case PragTyp_AUTO_VACUUM_SLACK_PAGES: {
++ Btree *pBt = pDb->pBt;
++ assert( pBt!=0 );
++ if( !zRight ){
++ returnSingleInt(v, sqlite3BtreeGetAutoVacuumSlackPages(pBt));
++ }else{
++ int nPages = 8;
++ if( sqlite3GetInt32(zRight, &nPages) ){
++ sqlite3BtreeSetAutoVacuumSlackPages(pBt, nPages);
++ }
++ }
++ break;
++ }
++#endif
++
+ #ifndef SQLITE_OMIT_PAGER_PRAGMAS
+ /*
+ ** PRAGMA [schema.]cache_size
+diff --git a/third_party/sqlite/src/src/pragma.h b/third_party/sqlite/src/src/pragma.h
+index 2c44bc1d0a75..aa0deec75146 100644
+--- a/third_party/sqlite/src/src/pragma.h
++++ b/third_party/sqlite/src/src/pragma.h
+@@ -7,51 +7,52 @@
+ /* 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_INCREMENTAL_VACUUM 16
+-#define PragTyp_INDEX_INFO 17
+-#define PragTyp_INDEX_LIST 18
+-#define PragTyp_INTEGRITY_CHECK 19
+-#define PragTyp_JOURNAL_MODE 20
+-#define PragTyp_JOURNAL_SIZE_LIMIT 21
+-#define PragTyp_LOCK_PROXY_FILE 22
+-#define PragTyp_LOCKING_MODE 23
+-#define PragTyp_PAGE_COUNT 24
+-#define PragTyp_MMAP_SIZE 25
+-#define PragTyp_MODULE_LIST 26
+-#define PragTyp_OPTIMIZE 27
+-#define PragTyp_PAGE_SIZE 28
+-#define PragTyp_PRAGMA_LIST 29
+-#define PragTyp_SECURE_DELETE 30
+-#define PragTyp_SHRINK_MEMORY 31
+-#define PragTyp_SOFT_HEAP_LIMIT 32
+-#define PragTyp_SYNCHRONOUS 33
+-#define PragTyp_TABLE_INFO 34
+-#define PragTyp_TEMP_STORE 35
+-#define PragTyp_TEMP_STORE_DIRECTORY 36
+-#define PragTyp_THREADS 37
+-#define PragTyp_WAL_AUTOCHECKPOINT 38
+-#define PragTyp_WAL_CHECKPOINT 39
+-#define PragTyp_ACTIVATE_EXTENSIONS 40
+-#define PragTyp_HEXKEY 41
+-#define PragTyp_KEY 42
+-#define PragTyp_REKEY 43
+-#define PragTyp_LOCK_STATUS 44
+-#define PragTyp_PARSER_TRACE 45
+-#define PragTyp_STATS 46
++#define PragTyp_AUTO_VACUUM_SLACK_PAGES 2
++#define PragTyp_FLAG 3
++#define PragTyp_BUSY_TIMEOUT 4
++#define PragTyp_CACHE_SIZE 5
++#define PragTyp_CACHE_SPILL 6
++#define PragTyp_CASE_SENSITIVE_LIKE 7
++#define PragTyp_COLLATION_LIST 8
++#define PragTyp_COMPILE_OPTIONS 9
++#define PragTyp_DATA_STORE_DIRECTORY 10
++#define PragTyp_DATABASE_LIST 11
++#define PragTyp_DEFAULT_CACHE_SIZE 12
++#define PragTyp_ENCODING 13
++#define PragTyp_FOREIGN_KEY_CHECK 14
++#define PragTyp_FOREIGN_KEY_LIST 15
++#define PragTyp_FUNCTION_LIST 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_HEXKEY 42
++#define PragTyp_KEY 43
++#define PragTyp_REKEY 44
++#define PragTyp_LOCK_STATUS 45
++#define PragTyp_PARSER_TRACE 46
++#define PragTyp_STATS 47
+
+ /* Property flags associated with various pragma. */
+ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */
+@@ -152,6 +153,11 @@ static const PragmaName aPragmaName[] = {
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
++ {/* zName: */ "auto_vacuum_slack_pages",
++ /* ePragTyp: */ PragTyp_AUTO_VACUUM_SLACK_PAGES,
++ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
++ /* ColNames: */ 0, 0,
++ /* iArg: */ 0 },
+ #endif
+ #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ #if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
+@@ -646,4 +652,4 @@ static const PragmaName aPragmaName[] = {
+ /* iArg: */ SQLITE_WriteSchema },
+ #endif
+ };
+-/* Number of pragmas: 60 on by default, 77 total. */
++/* Number of pragmas: 61 on by default, 78 total. */
+diff --git a/third_party/sqlite/src/tool/mkpragmatab.tcl b/third_party/sqlite/src/tool/mkpragmatab.tcl
+index f788eef425fc..0565c6699c20 100644
+--- a/third_party/sqlite/src/tool/mkpragmatab.tcl
++++ b/third_party/sqlite/src/tool/mkpragmatab.tcl
+@@ -382,6 +382,10 @@ set pragma_def {
+
+ NAME: optimize
+ FLAG: Result1 NeedSchema
++
++ NAME: auto_vacuum_slack_pages
++ FLAG: NeedSchema Result0 SchemaReq NoColumns1
++ IF: !defined(SQLITE_OMIT_AUTOVACUUM)
+ }
+
+ # Open the output file
+--
+2.14.0
diff --git a/third_party/sqlite/patches/0010-Allow-auto-vacuum-to-work-with-chunks.patch b/third_party/sqlite/patches/0010-Allow-auto-vacuum-to-work-with-chunks.patch
deleted file mode 100644
index f5f4f830..0000000
--- a/third_party/sqlite/patches/0010-Allow-auto-vacuum-to-work-with-chunks.patch
+++ /dev/null
@@ -1,302 +0,0 @@
-From d0ecdf49d28069fa070ce3fa653a0f1e2b03b3a8 Mon Sep 17 00:00:00 2001
-From: Scott Hess <shess@chromium.org>
-Date: Thu, 2 Mar 2017 15:23:09 -0800
-Subject: [PATCH 10/10] Allow auto-vacuum to work with chunks.
-
-SQLITE_FCNTL_CHUNK_SIZE can advise the VFS to resize files in quantum
-amounts, to reduce fragmentation from tiny appends. This change allows
-a new PRAGMA auto_vacuum_slack_pages to provide auto_vacuum with a hint
-to only rearrange pages when an entire quantum can be released.
-
-When rebasing this patch, first ignore the conflicts in src/pragma.h,
-and fix all the other conflicts. Then run the commands below (in
-third_party/sqlite) to re-generate src/pragma.h.
-tclsh src/tool/mkpragmatab.tcl
-find src/ -type f -iname "*.h" -exec \
- $GNU_SED --in-place 's/[[:space:]]\+$//' {} \+
-
-BUG=698010
----
- third_party/sqlite/src/src/btree.c | 56 ++++++++++++++++-
- third_party/sqlite/src/src/btree.h | 2 +
- third_party/sqlite/src/src/btreeInt.h | 1 +
- third_party/sqlite/src/src/pragma.c | 21 +++++++
- third_party/sqlite/src/src/pragma.h | 98 +++++++++++++++--------------
- third_party/sqlite/src/tool/mkpragmatab.tcl | 4 ++
- 6 files changed, 135 insertions(+), 47 deletions(-)
-
-diff --git a/third_party/sqlite/src/src/btree.c b/third_party/sqlite/src/src/btree.c
-index 53e467cf91f1..26c2d762e2e0 100644
---- a/third_party/sqlite/src/src/btree.c
-+++ b/third_party/sqlite/src/src/btree.c
-@@ -2909,6 +2909,46 @@ static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){
- # define setDefaultSyncFlag(pBt,safety_level)
- #endif
-
-+/*
-+** Change the 'auto-vacuum-slack-pages' property of the database. If auto vacuum
-+** is enabled, this is the number of chunks of slack to allow before
-+** automatically running an incremental vacuum.
-+*/
-+int sqlite3BtreeSetAutoVacuumSlackPages(Btree *p, int autoVacuumSlack){
-+#ifdef SQLITE_OMIT_AUTOVACUUM
-+ return SQLITE_READONLY;
-+#else
-+ BtShared *pBt = p->pBt;
-+ int rc = SQLITE_OK;
-+ u8 avs = (u8)autoVacuumSlack;
-+ if( autoVacuumSlack>avs ){
-+ avs = 0xFF;
-+ }
-+
-+ sqlite3BtreeEnter(p);
-+ pBt->autoVacuumSlack = avs;
-+ sqlite3BtreeLeave(p);
-+ return rc;
-+#endif
-+}
-+
-+/*
-+** Return the value of the 'auto-vacuum-slack-pages' property.
-+*/
-+int sqlite3BtreeGetAutoVacuumSlackPages(Btree *p){
-+#ifdef SQLITE_OMIT_AUTOVACUUM
-+ return 0;
-+#else
-+ int rc = 0;
-+ sqlite3BtreeEnter(p);
-+ if( p->pBt->autoVacuum!=0 ){
-+ rc = p->pBt->autoVacuumSlack;
-+ }
-+ sqlite3BtreeLeave(p);
-+ return rc;
-+#endif
-+}
-+
- /*
- ** Get a reference to pPage1 of the database file. This will
- ** also acquire a readlock on that file.
-@@ -3738,13 +3778,27 @@ int sqlite3BtreeIncrVacuum(Btree *p){
- */
- static int autoVacuumCommit(BtShared *pBt){
- int rc = SQLITE_OK;
-+ int bShouldVacuum = pBt->autoVacuum && !pBt->incrVacuum;
- Pager *pPager = pBt->pPager;
- VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager); )
-
- assert( sqlite3_mutex_held(pBt->mutex) );
- invalidateAllOverflowCache(pBt);
- assert(pBt->autoVacuum);
-- if( !pBt->incrVacuum ){
-+ if( bShouldVacuum && pBt->autoVacuumSlack ){
-+ Pgno nOrig; /* Database size before freeing */
-+ Pgno nFree; /* Number of pages on the freelist initially */
-+
-+ nOrig = btreePagecount(pBt);
-+ nFree = get4byte(&pBt->pPage1->aData[36]);
-+ bShouldVacuum =
-+ (nOrig-nFree-1)/pBt->autoVacuumSlack < (nOrig-1)/pBt->autoVacuumSlack;
-+ /* TODO: When integrating this test with the following code, contrive to
-+ ** trim to the integral chunk boundary, rather than trimming the entire free
-+ ** list.
-+ */
-+ }
-+ if( bShouldVacuum ){
- Pgno nFin; /* Number of pages in database after autovacuuming */
- Pgno nFree; /* Number of pages on the freelist initially */
- Pgno iFree; /* The next page to be freed */
-diff --git a/third_party/sqlite/src/src/btree.h b/third_party/sqlite/src/src/btree.h
-index ce607bd4d082..7ba2cab407db 100644
---- a/third_party/sqlite/src/src/btree.h
-+++ b/third_party/sqlite/src/src/btree.h
-@@ -78,6 +78,8 @@ int sqlite3BtreeGetOptimalReserve(Btree*);
- int sqlite3BtreeGetReserveNoMutex(Btree *p);
- int sqlite3BtreeSetAutoVacuum(Btree *, int);
- int sqlite3BtreeGetAutoVacuum(Btree *);
-+int sqlite3BtreeSetAutoVacuumSlackPages(Btree *, int);
-+int sqlite3BtreeGetAutoVacuumSlackPages(Btree *);
- int sqlite3BtreeBeginTrans(Btree*,int);
- int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
- int sqlite3BtreeCommitPhaseTwo(Btree*, int);
-diff --git a/third_party/sqlite/src/src/btreeInt.h b/third_party/sqlite/src/src/btreeInt.h
-index 9281f1640bd6..139a0abb7bfb 100644
---- a/third_party/sqlite/src/src/btreeInt.h
-+++ b/third_party/sqlite/src/src/btreeInt.h
-@@ -412,6 +412,7 @@ struct BtShared {
- u8 openFlags; /* Flags to sqlite3BtreeOpen() */
- #ifndef SQLITE_OMIT_AUTOVACUUM
- u8 autoVacuum; /* True if auto-vacuum is enabled */
-+ u8 autoVacuumSlack; /* Optional pages of slack for auto-vacuum */
- u8 incrVacuum; /* True if incr-vacuum is enabled */
- u8 bDoTruncate; /* True to truncate db on commit */
- #endif
-diff --git a/third_party/sqlite/src/src/pragma.c b/third_party/sqlite/src/src/pragma.c
-index 8ca64b2a04ec..fc73852c3930 100644
---- a/third_party/sqlite/src/src/pragma.c
-+++ b/third_party/sqlite/src/src/pragma.c
-@@ -756,6 +756,27 @@ void sqlite3Pragma(
- }
- #endif
-
-+ /*
-+ ** PRAGMA [schema.]auto_vacuum_slack_pages(N)
-+ **
-+ ** Control chunk size of auto-vacuum.
-+ */
-+#ifndef SQLITE_OMIT_AUTOVACUUM
-+ case PragTyp_AUTO_VACUUM_SLACK_PAGES: {
-+ Btree *pBt = pDb->pBt;
-+ assert( pBt!=0 );
-+ if( !zRight ){
-+ returnSingleInt(v, sqlite3BtreeGetAutoVacuumSlackPages(pBt));
-+ }else{
-+ int nPages = 8;
-+ if( sqlite3GetInt32(zRight, &nPages) ){
-+ sqlite3BtreeSetAutoVacuumSlackPages(pBt, nPages);
-+ }
-+ }
-+ break;
-+ }
-+#endif
-+
- #ifndef SQLITE_OMIT_PAGER_PRAGMAS
- /*
- ** PRAGMA [schema.]cache_size
-diff --git a/third_party/sqlite/src/src/pragma.h b/third_party/sqlite/src/src/pragma.h
-index 2c44bc1d0a75..aa0deec75146 100644
---- a/third_party/sqlite/src/src/pragma.h
-+++ b/third_party/sqlite/src/src/pragma.h
-@@ -7,51 +7,52 @@
- /* 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_INCREMENTAL_VACUUM 16
--#define PragTyp_INDEX_INFO 17
--#define PragTyp_INDEX_LIST 18
--#define PragTyp_INTEGRITY_CHECK 19
--#define PragTyp_JOURNAL_MODE 20
--#define PragTyp_JOURNAL_SIZE_LIMIT 21
--#define PragTyp_LOCK_PROXY_FILE 22
--#define PragTyp_LOCKING_MODE 23
--#define PragTyp_PAGE_COUNT 24
--#define PragTyp_MMAP_SIZE 25
--#define PragTyp_MODULE_LIST 26
--#define PragTyp_OPTIMIZE 27
--#define PragTyp_PAGE_SIZE 28
--#define PragTyp_PRAGMA_LIST 29
--#define PragTyp_SECURE_DELETE 30
--#define PragTyp_SHRINK_MEMORY 31
--#define PragTyp_SOFT_HEAP_LIMIT 32
--#define PragTyp_SYNCHRONOUS 33
--#define PragTyp_TABLE_INFO 34
--#define PragTyp_TEMP_STORE 35
--#define PragTyp_TEMP_STORE_DIRECTORY 36
--#define PragTyp_THREADS 37
--#define PragTyp_WAL_AUTOCHECKPOINT 38
--#define PragTyp_WAL_CHECKPOINT 39
--#define PragTyp_ACTIVATE_EXTENSIONS 40
--#define PragTyp_HEXKEY 41
--#define PragTyp_KEY 42
--#define PragTyp_REKEY 43
--#define PragTyp_LOCK_STATUS 44
--#define PragTyp_PARSER_TRACE 45
--#define PragTyp_STATS 46
-+#define PragTyp_AUTO_VACUUM_SLACK_PAGES 2
-+#define PragTyp_FLAG 3
-+#define PragTyp_BUSY_TIMEOUT 4
-+#define PragTyp_CACHE_SIZE 5
-+#define PragTyp_CACHE_SPILL 6
-+#define PragTyp_CASE_SENSITIVE_LIKE 7
-+#define PragTyp_COLLATION_LIST 8
-+#define PragTyp_COMPILE_OPTIONS 9
-+#define PragTyp_DATA_STORE_DIRECTORY 10
-+#define PragTyp_DATABASE_LIST 11
-+#define PragTyp_DEFAULT_CACHE_SIZE 12
-+#define PragTyp_ENCODING 13
-+#define PragTyp_FOREIGN_KEY_CHECK 14
-+#define PragTyp_FOREIGN_KEY_LIST 15
-+#define PragTyp_FUNCTION_LIST 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_HEXKEY 42
-+#define PragTyp_KEY 43
-+#define PragTyp_REKEY 44
-+#define PragTyp_LOCK_STATUS 45
-+#define PragTyp_PARSER_TRACE 46
-+#define PragTyp_STATS 47
-
- /* Property flags associated with various pragma. */
- #define PragFlg_NeedSchema 0x01 /* Force schema load before running */
-@@ -152,6 +153,11 @@ static const PragmaName aPragmaName[] = {
- /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
- /* ColNames: */ 0, 0,
- /* iArg: */ 0 },
-+ {/* zName: */ "auto_vacuum_slack_pages",
-+ /* ePragTyp: */ PragTyp_AUTO_VACUUM_SLACK_PAGES,
-+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
-+ /* ColNames: */ 0, 0,
-+ /* iArg: */ 0 },
- #endif
- #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- #if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
-@@ -646,4 +652,4 @@ static const PragmaName aPragmaName[] = {
- /* iArg: */ SQLITE_WriteSchema },
- #endif
- };
--/* Number of pragmas: 60 on by default, 77 total. */
-+/* Number of pragmas: 61 on by default, 78 total. */
-diff --git a/third_party/sqlite/src/tool/mkpragmatab.tcl b/third_party/sqlite/src/tool/mkpragmatab.tcl
-index f788eef425fc..0565c6699c20 100644
---- a/third_party/sqlite/src/tool/mkpragmatab.tcl
-+++ b/third_party/sqlite/src/tool/mkpragmatab.tcl
-@@ -382,6 +382,10 @@ set pragma_def {
-
- NAME: optimize
- FLAG: Result1 NeedSchema
-+
-+ NAME: auto_vacuum_slack_pages
-+ FLAG: NeedSchema Result0 SchemaReq NoColumns1
-+ IF: !defined(SQLITE_OMIT_AUTOVACUUM)
- }
-
- # Open the output file
---
-2.13.1.518.g3df882009-goog
-
diff --git a/third_party/sqlite/patches/0010-fuchsia-Use-dot-file-locking-for-sqlite.patch b/third_party/sqlite/patches/0010-fuchsia-Use-dot-file-locking-for-sqlite.patch
new file mode 100644
index 0000000..fc37cb15
--- /dev/null
+++ b/third_party/sqlite/patches/0010-fuchsia-Use-dot-file-locking-for-sqlite.patch
@@ -0,0 +1,26 @@
+From 2d48d6d294f5fdd0008b0b9e9958c87ce207b593 Mon Sep 17 00:00:00 2001
+From: Scott Graham <scottmg@chromium.org>
+Date: Mon, 11 Sep 2017 13:37:46 -0700
+Subject: [PATCH 10/10] fuchsia: Use dot-file locking for sqlite
+
+---
+ third_party/sqlite/src/src/os_unix.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/third_party/sqlite/src/src/os_unix.c b/third_party/sqlite/src/src/os_unix.c
+index 6ed6f6a8fc98..dc3018801aae 100644
+--- a/third_party/sqlite/src/src/os_unix.c
++++ b/third_party/sqlite/src/src/os_unix.c
+@@ -7675,6 +7675,10 @@ int sqlite3_os_init(void){
+ UNIXVFS("unix", autolockIoFinder ),
+ #elif OS_VXWORKS
+ UNIXVFS("unix", vxworksIoFinder ),
++#elif __Fuchsia__
++ /* None of the system calls for other exclusion methods are currently
++ ** implemented on Fuchsia, so use simple dot-file locking for now. */
++ UNIXVFS("unix", dotlockIoFinder ),
+ #else
+ UNIXVFS("unix", posixIoFinder ),
+ #endif
+--
+2.14.0
diff --git a/third_party/sqlite/src/Makefile.in b/third_party/sqlite/src/Makefile.in
index 358e777..a0f71d7 100644
--- a/third_party/sqlite/src/Makefile.in
+++ b/third_party/sqlite/src/Makefile.in
@@ -166,7 +166,8 @@ USE_AMALGAMATION = @USE_AMALGAMATION@
#
LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
backup.lo bitvec.lo btmutex.lo btree.lo build.lo \
- callback.lo complete.lo ctime.lo date.lo dbstat.lo delete.lo \
+ callback.lo complete.lo ctime.lo \
+ date.lo dbpage.lo dbstat.lo delete.lo \
expr.lo fault.lo fkey.lo \
fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
@@ -215,6 +216,7 @@ SRC = \
$(TOP)/src/complete.c \
$(TOP)/src/ctime.c \
$(TOP)/src/date.c \
+ $(TOP)/src/dbpage.c \
$(TOP)/src/dbstat.c \
$(TOP)/src/delete.c \
$(TOP)/src/expr.c \
@@ -265,7 +267,7 @@ SRC = \
$(TOP)/src/rowset.c \
$(TOP)/src/select.c \
$(TOP)/src/status.c \
- $(TOP)/src/shell.c \
+ $(TOP)/src/shell.c.in \
$(TOP)/src/sqlite.h.in \
$(TOP)/src/sqlite3ext.h \
$(TOP)/src/sqliteInt.h \
@@ -362,6 +364,7 @@ SRC += \
parse.c \
parse.h \
config.h \
+ shell.c \
sqlite3.h
# Source code to the test files.
@@ -393,6 +396,7 @@ TESTSRC = \
$(TOP)/src/test_intarray.c \
$(TOP)/src/test_journal.c \
$(TOP)/src/test_malloc.c \
+ $(TOP)/src/test_md5.c \
$(TOP)/src/test_multiplex.c \
$(TOP)/src/test_mutex.c \
$(TOP)/src/test_onefile.c \
@@ -404,6 +408,7 @@ TESTSRC = \
$(TOP)/src/test_server.c \
$(TOP)/src/test_superlock.c \
$(TOP)/src/test_syscall.c \
+ $(TOP)/src/test_tclsh.c \
$(TOP)/src/test_tclvar.c \
$(TOP)/src/test_thread.c \
$(TOP)/src/test_vfs.c \
@@ -428,6 +433,7 @@ TESTSRC += \
$(TOP)/ext/fts5/fts5_test_mi.c \
$(TOP)/ext/fts5/fts5_test_tok.c \
$(TOP)/ext/misc/ieee754.c \
+ $(TOP)/ext/misc/mmapwarm.c \
$(TOP)/ext/misc/nextchar.c \
$(TOP)/ext/misc/percentile.c \
$(TOP)/ext/misc/regexp.c \
@@ -448,6 +454,7 @@ TESTSRC2 = \
$(TOP)/src/build.c \
$(TOP)/src/ctime.c \
$(TOP)/src/date.c \
+ $(TOP)/src/dbpage.c \
$(TOP)/src/dbstat.c \
$(TOP)/src/expr.c \
$(TOP)/src/func.c \
@@ -568,6 +575,8 @@ SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
+SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
+SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
@@ -596,9 +605,9 @@ libtclsqlite3.la: tclsqlite.lo libsqlite3.la
-version-info "8:6:8" \
-avoid-version
-sqlite3$(TEXE): $(TOP)/src/shell.c sqlite3.c
+sqlite3$(TEXE): shell.c sqlite3.c
$(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \
- $(TOP)/src/shell.c sqlite3.c \
+ shell.c sqlite3.c \
$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"
sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.lo sqlite3.h
@@ -693,6 +702,11 @@ lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
$(BCC) -o $@ $(TOP)/tool/lemon.c
cp $(TOP)/tool/lempar.c .
+# Rules to build the program that generates the source-id
+#
+mksourceid$(BEXE): $(TOP)/tool/mksourceid.c
+ $(BCC) -o $@ $(TOP)/tool/mksourceid.c
+
# Rules to build individual *.o files from generated *.c files. This
# applies to:
#
@@ -746,6 +760,9 @@ ctime.lo: $(TOP)/src/ctime.c $(HDR)
date.lo: $(TOP)/src/date.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/date.c
+dbpage.lo: $(TOP)/src/dbpage.c $(HDR)
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/dbpage.c
+
dbstat.lo: $(TOP)/src/dbstat.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/dbstat.c
@@ -930,7 +947,7 @@ tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -c $(TOP)/src/tclsqlite.c
tclsqlite-shell.lo: $(TOP)/src/tclsqlite.c $(HDR)
- $(LTCOMPILE) -DTCLSH=1 -o $@ -c $(TOP)/src/tclsqlite.c
+ $(LTCOMPILE) -DTCLSH -o $@ -c $(TOP)/src/tclsqlite.c
tclsqlite-stubs.lo: $(TOP)/src/tclsqlite.c $(HDR)
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -o $@ -c $(TOP)/src/tclsqlite.c
@@ -958,13 +975,24 @@ parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/tool/addopcodes.tcl
mv parse.h parse.h.temp
$(TCLSH_CMD) $(TOP)/tool/addopcodes.tcl parse.h.temp >parse.h
-sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION
+sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION
$(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c
./mkkeywordhash$(BEXE) >keywordhash.h
+# Source files that go into making shell.c
+SHELL_SRC = \
+ $(TOP)/src/shell.c.in \
+ $(TOP)/ext/misc/shathree.c \
+ $(TOP)/ext/misc/fileio.c \
+ $(TOP)/ext/misc/completion.c
+
+shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
+ $(TCLSH_CMD) $(TOP)/tool/mkshellc.tcl >shell.c
+
+
# Rules to build the extension objects.
@@ -1085,12 +1113,14 @@ sqlite3rbu.lo: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR)
# necessary because the test fixture requires non-API symbols which are
# hidden when the library is built via the amalgamation).
#
-TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
+TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
+TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
TESTFIXTURE_FLAGS += -DBUILD_sqlite
TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
+TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
TESTFIXTURE_SRC1 = sqlite3.c
@@ -1151,14 +1181,8 @@ valgrindtest: $(TESTPROGS) valgrindfuzz
smoketest: $(TESTPROGS) fuzzcheck$(TEXE)
./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS)
-sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl
- echo "#define TCLSH 2" > $@
- echo "#define SQLITE_ENABLE_DBSTAT_VTAB 1" >> $@
- cat sqlite3.c $(TOP)/src/tclsqlite.c >> $@
- echo "static const char *tclsh_main_loop(void){" >> $@
- echo "static const char *zMainloop = " >> $@
- $(TCLSH_CMD) $(TOP)/tool/tostr.tcl $(TOP)/tool/spaceanal.tcl >> $@
- echo "; return zMainloop; }" >> $@
+sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in
+ $(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
diff --git a/third_party/sqlite/src/Makefile.msc b/third_party/sqlite/src/Makefile.msc
index da94288c..2804c25 100644
--- a/third_party/sqlite/src/Makefile.msc
+++ b/third_party/sqlite/src/Makefile.msc
@@ -1091,7 +1091,8 @@ LTLIBS = $(LTLIBS) $(LIBICU)
#
LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
backup.lo bitvec.lo btmutex.lo btree.lo build.lo \
- callback.lo complete.lo ctime.lo date.lo dbstat.lo delete.lo \
+ callback.lo complete.lo ctime.lo \
+ date.lo dbpage.lo dbstat.lo delete.lo \
expr.lo fault.lo fkey.lo \
fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
@@ -1154,6 +1155,7 @@ SRC00 = \
$(TOP)\src\complete.c \
$(TOP)\src\ctime.c \
$(TOP)\src\date.c \
+ $(TOP)\src\dbpage.c \
$(TOP)\src\dbstat.c \
$(TOP)\src\delete.c \
$(TOP)\src\expr.c \
@@ -1220,11 +1222,6 @@ SRC01 = \
$(TOP)\src\wherecode.c \
$(TOP)\src\whereexpr.c
-# Shell source code files.
-#
-SRC02 = \
- $(TOP)\src\shell.c
-
# Core miscellaneous files.
#
SRC03 = \
@@ -1331,6 +1328,7 @@ SRC11 = \
keywordhash.h \
opcodes.h \
parse.h \
+ shell.c \
$(SQLITE3H)
# Generated Tcl header files
@@ -1345,7 +1343,7 @@ SRC12 =
# All source code files.
#
-SRC = $(SRC00) $(SRC01) $(SRC02) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11)
+SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11)
# Source code to the test files.
#
@@ -1376,6 +1374,7 @@ TESTSRC = \
$(TOP)\src\test_intarray.c \
$(TOP)\src\test_journal.c \
$(TOP)\src\test_malloc.c \
+ $(TOP)\src\test_md5.c \
$(TOP)\src\test_multiplex.c \
$(TOP)\src\test_mutex.c \
$(TOP)\src\test_onefile.c \
@@ -1387,6 +1386,7 @@ TESTSRC = \
$(TOP)\src\test_server.c \
$(TOP)\src\test_superlock.c \
$(TOP)\src\test_syscall.c \
+ $(TOP)\src\test_tclsh.c \
$(TOP)\src\test_tclvar.c \
$(TOP)\src\test_thread.c \
$(TOP)\src\test_vfs.c \
@@ -1411,6 +1411,7 @@ TESTEXT = \
$(TOP)\ext\fts5\fts5_test_mi.c \
$(TOP)\ext\fts5\fts5_test_tok.c \
$(TOP)\ext\misc\ieee754.c \
+ $(TOP)\ext\misc\mmapwarm.c \
$(TOP)\ext\misc\nextchar.c \
$(TOP)\ext\misc\percentile.c \
$(TOP)\ext\misc\regexp.c \
@@ -1507,13 +1508,14 @@ FUZZDATA = \
# when the shell is not being dynamically linked.
#
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
-SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
+SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
+SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB
!ENDIF
# <<mark>>
# Extra compiler options for various test tools.
#
-MPTESTER_COMPILE_OPTS = -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS5
+MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5
FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1
FUZZCHECK_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000
FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c
@@ -1568,8 +1570,8 @@ sqlite3.def: libsqlite3.lib
| sort >> sqlite3.def
# <</block2>>
-$(SQLITE3EXE): $(TOP)\src\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
- $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\shell.c $(SHELL_CORE_SRC) \
+$(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
+ $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) shell.c $(SHELL_CORE_SRC) \
/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
# <<mark>>
@@ -1628,7 +1630,6 @@ mptest: mptester.exe
-mkdir tsrc
for %i in ($(SRC00)) do copy /Y %i tsrc
for %i in ($(SRC01)) do copy /Y %i tsrc
- for %i in ($(SRC02)) do copy /Y %i tsrc
for %i in ($(SRC03)) do copy /Y %i tsrc
for %i in ($(SRC04)) do copy /Y %i tsrc
for %i in ($(SRC05)) do copy /Y %i tsrc
@@ -1670,6 +1671,12 @@ lemon.exe: $(TOP)\tool\lemon.c lempar.c
$(BCC) $(NO_WARN) -Daccess=_access \
-Fe$@ $(TOP)\tool\lemon.c /link $(LDFLAGS) $(NLTLINKOPTS) $(NLTLIBPATHS)
+# <<mark>>
+# Rules to build the source-id generator tool
+#
+mksourceid.exe: $(TOP)\tool\mksourceid.c
+ $(BCC) $(NO_WARN) -Fe$@ $(TOP)\tool\mksourceid.c /link $(LDFLAGS) $(NLTLINKOPTS) $(NLTLIBPATHS)
+
# Rules to build individual *.lo files from generated *.c files. This
# applies to:
#
@@ -1740,7 +1747,10 @@ ctime.lo: $(TOP)\src\ctime.c $(HDR)
date.lo: $(TOP)\src\date.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\date.c
-dbstat.lo: $(TOP)\src\date.c $(HDR)
+dbpage.lo: $(TOP)\src\dbpage.c $(HDR)
+ $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\dbpage.c
+
+dbstat.lo: $(TOP)\src\dbstat.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\dbstat.c
delete.lo: $(TOP)\src\delete.c $(HDR)
@@ -1924,7 +1934,7 @@ tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
$(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
tclsqlite-shell.lo: $(TOP)\src\tclsqlite.c $(HDR) $(SQLITE_TCL_DEP)
- $(LTCOMPILE) $(NO_WARN) -DTCLSH=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
+ $(LTCOMPILE) $(NO_WARN) -DTCLSH -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c
tclsqlite3.exe: tclsqlite-shell.lo $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
$(LTLINK) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /OUT:$@ tclsqlite-shell.lo $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
@@ -1948,7 +1958,7 @@ parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\tool\addopcodes.tcl
move parse.h parse.h.temp
$(TCLSH_CMD) $(TOP)\tool\addopcodes.tcl parse.h.temp > parse.h
-$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest.uuid $(TOP)\VERSION
+$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION
$(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > $(SQLITE3H) $(MKSQLITE3H_ARGS)
sqlite3ext.h: .target_source
@@ -1967,6 +1977,15 @@ mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c
keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
.\mkkeywordhash.exe > keywordhash.h
+# Source files that go into making shell.c
+SHELL_SRC = \
+ $(TOP)\src\shell.c.in \
+ $(TOP)\ext\misc\shathree.c \
+ $(TOP)\ext\misc\fileio.c \
+ $(TOP)\ext\misc\completion.c
+
+shell.c: $(SHELL_SRC) $(TOP)\tool\mkshellc.tcl
+ $(TCLSH_CMD) $(TOP)\tool\mkshellc.tcl > shell.c
# Rules to build the extension objects.
@@ -2086,12 +2105,13 @@ sqlite3rbu.lo: $(TOP)\ext\rbu\sqlite3rbu.c $(HDR) $(EXTHDR)
# necessary because the test fixture requires non-API symbols which are
# hidden when the library is built via the amalgamation).
#
-TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
+TESTFIXTURE_FLAGS = -DTCLSH_INIT_PROC=sqlite3TestInit -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE=""
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN)
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB
+TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
@@ -2171,14 +2191,8 @@ smoketest: $(TESTPROGS)
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\main.test $(TESTOPTS)
-sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(SQLITE_TCL_DEP)
- echo #define TCLSH 2 > $@
- echo #define SQLITE_ENABLE_DBSTAT_VTAB 1 >> $@
- copy $@ + $(SQLITE3C) + $(TOP)\src\tclsqlite.c $@
- echo static const char *tclsh_main_loop(void){ >> $@
- echo static const char *zMainloop = >> $@
- $(TCLSH_CMD) $(TOP)\tool\tostr.tcl $(TOP)\tool\spaceanal.tcl >> $@
- echo ; return zMainloop; } >> $@
+sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(SQLITE_TCL_DEP)
+ $(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@
sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
@@ -2260,7 +2274,7 @@ clean:
del /Q sqlite3.c sqlite3.h 2>NUL
del /Q opcodes.c opcodes.h 2>NUL
del /Q lemon.* lempar.c parse.* 2>NUL
- del /Q mkkeywordhash.* keywordhash.h 2>NUL
+ del /Q mksourceid.* mkkeywordhash.* keywordhash.h 2>NUL
del /Q notasharedlib.* 2>NUL
-rmdir /Q/S .deps 2>NUL
-rmdir /Q/S .libs 2>NUL
diff --git a/third_party/sqlite/src/VERSION b/third_party/sqlite/src/VERSION
index eb9b76c..6075c9a 100644
--- a/third_party/sqlite/src/VERSION
+++ b/third_party/sqlite/src/VERSION
@@ -1 +1 @@
-3.20.0
+3.21.0
diff --git a/third_party/sqlite/src/autoconf/Makefile.am b/third_party/sqlite/src/autoconf/Makefile.am
index e821159..8c046f8 100644
--- a/third_party/sqlite/src/autoconf/Makefile.am
+++ b/third_party/sqlite/src/autoconf/Makefile.am
@@ -10,7 +10,7 @@ sqlite3_SOURCES = shell.c sqlite3.h
EXTRA_sqlite3_SOURCES = sqlite3.c
sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
-sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS
+sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB
include_HEADERS = sqlite3.h sqlite3ext.h
diff --git a/third_party/sqlite/src/autoconf/Makefile.msc b/third_party/sqlite/src/autoconf/Makefile.msc
index 9f86798..e0f7ad8 100644
--- a/third_party/sqlite/src/autoconf/Makefile.msc
+++ b/third_party/sqlite/src/autoconf/Makefile.msc
@@ -927,7 +927,8 @@ LIBRESOBJS =
# when the shell is not being dynamically linked.
#
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
-SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_SHELL_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS
+SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
+SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB
!ENDIF
@@ -957,8 +958,8 @@ sqlite3.def: Replace.exe $(LIBOBJ)
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
| sort >> sqlite3.def
-$(SQLITE3EXE): $(TOP)\shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
- $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\shell.c $(SHELL_CORE_SRC) \
+$(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
+ $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) shell.c $(SHELL_CORE_SRC) \
/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
diff --git a/third_party/sqlite/src/configure b/third_party/sqlite/src/configure
index eb860d48..64b95e9 100755
--- a/third_party/sqlite/src/configure
+++ b/third_party/sqlite/src/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for sqlite 3.20.0.
+# Generated by GNU Autoconf 2.69 for sqlite 3.21.0.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -726,8 +726,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
-PACKAGE_VERSION='3.20.0'
-PACKAGE_STRING='sqlite 3.20.0'
+PACKAGE_VERSION='3.21.0'
+PACKAGE_STRING='sqlite 3.21.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -909,6 +909,7 @@ enable_fts3
enable_fts4
enable_fts5
enable_json1
+enable_update_limit
enable_rtree
enable_session
enable_gcov
@@ -1463,7 +1464,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures sqlite 3.20.0 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.21.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1528,7 +1529,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.20.0:";;
+ short | recursive ) echo "Configuration of sqlite 3.21.0:";;
esac
cat <<\_ACEOF
@@ -1560,6 +1561,7 @@ Optional Features:
--enable-fts4 Enable the FTS4 extension
--enable-fts5 Enable the FTS5 extension
--enable-json1 Enable the JSON1 extension
+ --enable-update-limit Enable the UPDATE/DELETE LIMIT clause
--enable-rtree Enable the RTREE extension
--enable-session Enable the SESSION extension
--enable-gcov Enable coverage testing using gcov
@@ -1652,7 +1654,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sqlite configure 3.20.0
+sqlite configure 3.21.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2071,7 +2073,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by sqlite $as_me 3.20.0, which was
+It was created by sqlite $as_me 3.21.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3929,13 +3931,13 @@ if ${lt_cv_nm_interface+:} false; then :
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
- (eval echo "\"\$as_me:3932: $ac_compile\"" >&5)
+ (eval echo "\"\$as_me:3934: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
- (eval echo "\"\$as_me:3935: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval echo "\"\$as_me:3937: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
- (eval echo "\"\$as_me:3938: output\"" >&5)
+ (eval echo "\"\$as_me:3940: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -5141,7 +5143,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 5144 "configure"' > conftest.$ac_ext
+ echo '#line 5146 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -6666,11 +6668,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:6669: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:6671: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:6673: \$? = $ac_status" >&5
+ echo "$as_me:6675: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7005,11 +7007,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7008: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7010: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:7012: \$? = $ac_status" >&5
+ echo "$as_me:7014: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7110,11 +7112,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7113: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7115: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:7117: \$? = $ac_status" >&5
+ echo "$as_me:7119: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -7165,11 +7167,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7168: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7170: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:7172: \$? = $ac_status" >&5
+ echo "$as_me:7174: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -9545,7 +9547,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 9548 "configure"
+#line 9550 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -9641,7 +9643,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 9644 "configure"
+#line 9646 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10302,7 +10304,7 @@ USE_AMALGAMATION=1
# if not, then we fall back to plain tclsh.
# TODO: try other versions before falling back?
#
-for ac_prog in tclsh8.6 tclsh8.5 tclsh
+for ac_prog in tclsh8.7 tclsh8.6 tclsh8.5 tclsh
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
@@ -11540,6 +11542,20 @@ if test "${enable_json1}" = "yes" ; then
fi
#########
+# See whether we should enable the LIMIT clause on UPDATE and DELETE
+# statements.
+# Check whether --enable-update-limit was given.
+if test "${enable_update_limit+set}" = set; then :
+ enableval=$enable_update_limit; enable_udlimit=yes
+else
+ enable_udlimit=no
+fi
+
+if test "${enable_udlimit}" = "yes" ; then
+ OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
+fi
+
+#########
# See whether we should enable RTREE
# Check whether --enable-rtree was given.
if test "${enable_rtree+set}" = set; then :
@@ -12151,7 +12167,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by sqlite $as_me 3.20.0, which was
+This file was extended by sqlite $as_me 3.21.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12217,7 +12233,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-sqlite config.status 3.20.0
+sqlite config.status 3.21.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/third_party/sqlite/src/configure.ac b/third_party/sqlite/src/configure.ac
index 39179cc..7adb3e7 100644
--- a/third_party/sqlite/src/configure.ac
+++ b/third_party/sqlite/src/configure.ac
@@ -120,7 +120,7 @@ USE_AMALGAMATION=1
# if not, then we fall back to plain tclsh.
# TODO: try other versions before falling back?
#
-AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.6 tclsh8.5 tclsh], none)
+AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.7 tclsh8.6 tclsh8.5 tclsh], none)
if test "$TCLSH_CMD" = "none"; then
# If we can't find a local tclsh, then building the amalgamation will fail.
# We act as though --disable-amalgamation has been used.
@@ -645,6 +645,16 @@ if test "${enable_json1}" = "yes" ; then
fi
#########
+# See whether we should enable the LIMIT clause on UPDATE and DELETE
+# statements.
+AC_ARG_ENABLE(update-limit, AC_HELP_STRING([--enable-update-limit],
+ [Enable the UPDATE/DELETE LIMIT clause]),
+ [enable_udlimit=yes],[enable_udlimit=no])
+if test "${enable_udlimit}" = "yes" ; then
+ OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
+fi
+
+#########
# See whether we should enable RTREE
AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree],
[Enable the RTREE extension]),
diff --git a/third_party/sqlite/src/doc/lemon.html b/third_party/sqlite/src/doc/lemon.html
index db82862..eb6ff12 100644
--- a/third_party/sqlite/src/doc/lemon.html
+++ b/third_party/sqlite/src/doc/lemon.html
@@ -2,12 +2,12 @@
<head>
<title>The Lemon Parser Generator</title>
</head>
-<body bgcolor=white>
-<h1 align=center>The Lemon Parser Generator</h1>
+<body bgcolor='white'>
+<h1 align='center'>The Lemon Parser Generator</h1>
<p>Lemon is an LALR(1) parser generator for C.
It does the same job as "bison" and "yacc".
-But lemon is not a bison or yacc clone. Lemon
+But Lemon is not a bison or yacc clone. Lemon
uses a different grammar syntax which is designed to
reduce the number of coding errors. Lemon also uses a
parsing engine that is faster than yacc and
@@ -16,7 +16,7 @@ bison and which is both reentrant and threadsafe.
has also been updated so that it too can generate a
reentrant and threadsafe parser.)
Lemon also implements features that can be used
-to eliminate resource leaks, making is suitable for use
+to eliminate resource leaks, making it suitable for use
in long-running programs such as graphical user interfaces
or embedded controllers.</p>
@@ -58,8 +58,8 @@ Lemon comes with a default parser template which works fine for most
applications. But the user is free to substitute a different parser
template if desired.</p>
-<p>Depending on command-line options, Lemon will generate between
-one and three files of outputs.
+<p>Depending on command-line options, Lemon will generate up to
+three output files.
<ul>
<li>C code to implement the parser.
<li>A header file defining an integer ID for each terminal symbol.
@@ -90,17 +90,20 @@ the states used by the parser automaton.</p>
You can obtain a list of the available command-line options together
with a brief explanation of what each does by typing
<pre>
- lemon -?
+ lemon "-?"
</pre>
As of this writing, the following command-line options are supported:
<ul>
<li><b>-b</b>
Show only the basis for each parser state in the report file.
<li><b>-c</b>
-Do not compress the generated action tables.
+Do not compress the generated action tables. The parser will be a
+little larger and slower, but it will detect syntax errors sooner.
<li><b>-D<i>name</i></b>
-Define C preprocessor macro <i>name</i>. This macro is useable by
-"%ifdef" lines in the grammar file.
+Define C preprocessor macro <i>name</i>. This macro is usable by
+"<tt><a href='#pifdef'>%ifdef</a></tt>" and
+"<tt><a href='#pifdef'>%ifndef</a></tt>" lines
+in the grammar file.
<li><b>-g</b>
Do not generate a parser. Instead write the input grammar to standard
output with all comments, actions, and other extraneous text removed.
@@ -165,7 +168,7 @@ once for each token:
</pre>
The first argument to the Parse() routine is the pointer returned by
ParseAlloc().
-The second argument is a small positive integer that tells the parse the
+The second argument is a small positive integer that tells the parser the
type of the next token in the data stream.
There is one token type for each terminal symbol in the grammar.
The gram.h file generated by Lemon contains #define statements that
@@ -173,7 +176,7 @@ map symbolic terminal symbol names into appropriate integer values.
A value of 0 for the second argument is a special flag to the
parser to indicate that the end of input has been reached.
The third argument is the value of the given token. By default,
-the type of the third argument is integer, but the grammar will
+the type of the third argument is "void*", but the grammar will
usually redefine this type to be some kind of structure.
Typically the second argument will be a broad category of tokens
such as "identifier" or "number" and the third argument will
@@ -181,7 +184,7 @@ be the name of the identifier or the value of the number.</p>
<p>The Parse() function may have either three or four arguments,
depending on the grammar. If the grammar specification file requests
-it (via the <a href='#extraarg'><tt>extra_argument</tt> directive</a>),
+it (via the <tt><a href='#extraarg'>%extra_argument</a></tt> directive),
the Parse() function will have a fourth parameter that can be
of any type chosen by the programmer. The parser doesn't do anything
with this argument except to pass it through to action routines.
@@ -191,20 +194,20 @@ to the action routines without having to use global variables.</p>
<p>A typical use of a Lemon parser might look something like the
following:
<pre>
- 01 ParseTree *ParseFile(const char *zFilename){
- 02 Tokenizer *pTokenizer;
- 03 void *pParser;
- 04 Token sToken;
- 05 int hTokenId;
- 06 ParserState sState;
- 07
- 08 pTokenizer = TokenizerCreate(zFilename);
- 09 pParser = ParseAlloc( malloc );
- 10 InitParserState(&sState);
- 11 while( GetNextToken(pTokenizer, &hTokenId, &sToken) ){
- 12 Parse(pParser, hTokenId, sToken, &sState);
+ 1 ParseTree *ParseFile(const char *zFilename){
+ 2 Tokenizer *pTokenizer;
+ 3 void *pParser;
+ 4 Token sToken;
+ 5 int hTokenId;
+ 6 ParserState sState;
+ 7
+ 8 pTokenizer = TokenizerCreate(zFilename);
+ 9 pParser = ParseAlloc( malloc );
+ 10 InitParserState(&amp;sState);
+ 11 while( GetNextToken(pTokenizer, &amp;hTokenId, &amp;sToken) ){
+ 12 Parse(pParser, hTokenId, sToken, &amp;sState);
13 }
- 14 Parse(pParser, 0, sToken, &sState);
+ 14 Parse(pParser, 0, sToken, &amp;sState);
15 ParseFree(pParser, free );
16 TokenizerFree(pTokenizer);
17 return sState.treeRoot;
@@ -220,7 +223,7 @@ on line 16. The GetNextToken() function on line 11 retrieves the
next token from the input file and puts its type in the
integer variable hTokenId. The sToken variable is assumed to be
some kind of structure that contains details about each token,
-such as its complete text, what line it occurs on, etc. </p>
+such as its complete text, what line it occurs on, etc.</p>
<p>This example also assumes the existence of structure of type
ParserState that holds state information about a particular parse.
@@ -237,7 +240,7 @@ tree.</p>
<pre>
ParseFile(){
pParser = ParseAlloc( malloc );
- while( GetNextToken(pTokenizer,&hTokenId, &sToken) ){
+ while( GetNextToken(pTokenizer,&amp;hTokenId, &amp;sToken) ){
Parse(pParser, hTokenId, sToken);
}
Parse(pParser, 0, sToken);
@@ -297,23 +300,23 @@ specifies additional information Lemon requires to do its job.
Most of the work in using Lemon is in writing an appropriate
grammar file.</p>
-<p>The grammar file for lemon is, for the most part, free format.
+<p>The grammar file for Lemon is, for the most part, free format.
It does not have sections or divisions like yacc or bison. Any
declaration can occur at any point in the file.
Lemon ignores whitespace (except where it is needed to separate
-tokens) and it honors the same commenting conventions as C and C++.</p>
+tokens), and it honors the same commenting conventions as C and C++.</p>
<h3>Terminals and Nonterminals</h3>
<p>A terminal symbol (token) is any string of alphanumeric
and/or underscore characters
-that begins with an upper case letter.
+that begins with an uppercase letter.
A terminal can contain lowercase letters after the first character,
-but the usual convention is to make terminals all upper case.
+but the usual convention is to make terminals all uppercase.
A nonterminal, on the other hand, is any string of alphanumeric
-and underscore characters than begins with a lower case letter.
-Again, the usual convention is to make nonterminals use all lower
-case letters.</p>
+and underscore characters than begins with a lowercase letter.
+Again, the usual convention is to make nonterminals use all lowercase
+letters.</p>
<p>In Lemon, terminal and nonterminal symbols do not need to
be declared or identified in a separate section of the grammar file.
@@ -339,7 +342,8 @@ The list of terminals and nonterminals on the right-hand side of the
rule can be empty.
Rules can occur in any order, except that the left-hand side of the
first rule is assumed to be the start symbol for the grammar (unless
-specified otherwise using the <tt>%start</tt> directive described below.)
+specified otherwise using the <tt><a href='#start_symbol'>%start_symbol</a></tt>
+directive described below.)
A typical sequence of grammar rules might look something like this:
<pre>
expr ::= expr PLUS expr.
@@ -382,7 +386,7 @@ names to each symbol in a grammar rule and then using those symbolic
names in the action.
In yacc or bison, one would write this:
<pre>
- expr -> expr PLUS expr { $$ = $1 + $3; };
+ expr -&gt; expr PLUS expr { $$ = $1 + $3; };
</pre>
But in Lemon, the same rule becomes the following:
<pre>
@@ -423,13 +427,13 @@ whichever rule comes first in the grammar file.</p>
<p>Just like in
yacc and bison, Lemon allows a measure of control
-over the resolution of paring conflicts using precedence rules.
+over the resolution of parsing conflicts using precedence rules.
A precedence value can be assigned to any terminal symbol
using the
-<a href='#pleft'>%left</a>,
-<a href='#pright'>%right</a> or
-<a href='#pnonassoc'>%nonassoc</a> directives. Terminal symbols
-mentioned in earlier directives have a lower precedence that
+<tt><a href='#pleft'>%left</a></tt>,
+<tt><a href='#pright'>%right</a></tt> or
+<tt><a href='#pnonassoc'>%nonassoc</a></tt> directives. Terminal symbols
+mentioned in earlier directives have a lower precedence than
terminal symbols mentioned in later directives. For example:</p>
<p><pre>
@@ -505,29 +509,29 @@ as follows:
<li> If the precedence of the token to be shifted is greater than
the precedence of the rule to reduce, then resolve in favor
of the shift. No parsing conflict is reported.
-<li> If the precedence of the token it be shifted is less than the
+<li> If the precedence of the token to be shifted is less than the
precedence of the rule to reduce, then resolve in favor of the
reduce action. No parsing conflict is reported.
<li> If the precedences are the same and the shift token is
right-associative, then resolve in favor of the shift.
No parsing conflict is reported.
-<li> If the precedences are the same the shift token is
+<li> If the precedences are the same and the shift token is
left-associative, then resolve in favor of the reduce.
No parsing conflict is reported.
-<li> Otherwise, resolve the conflict by doing the shift and
- report the parsing conflict.
+<li> Otherwise, resolve the conflict by doing the shift, and
+ report a parsing conflict.
</ul>
Reduce-reduce conflicts are resolved this way:
<ul>
<li> If either reduce rule
lacks precedence information, then resolve in favor of the
- rule that appears first in the grammar and report a parsing
+ rule that appears first in the grammar, and report a parsing
conflict.
-<li> If both rules have precedence and the precedence is different
+<li> If both rules have precedence and the precedence is different,
then resolve the dispute in favor of the rule with the highest
- precedence and do not report a conflict.
+ precedence, and do not report a conflict.
<li> Otherwise, resolve the conflict by reducing by the rule that
- appears first in the grammar and report a parsing conflict.
+ appears first in the grammar, and report a parsing conflict.
</ul>
<h3>Special Directives</h3>
@@ -536,40 +540,40 @@ Reduce-reduce conflicts are resolved this way:
directives. We've described all the grammar rules, so now we'll
talk about the special directives.</p>
-<p>Directives in lemon can occur in any order. You can put them before
-the grammar rules, or after the grammar rules, or in the mist of the
+<p>Directives in Lemon can occur in any order. You can put them before
+the grammar rules, or after the grammar rules, or in the midst of the
grammar rules. It doesn't matter. The relative order of
directives used to assign precedence to terminals is important, but
other than that, the order of directives in Lemon is arbitrary.</p>
<p>Lemon supports the following special directives:
<ul>
-<li><tt>%code</tt>
-<li><tt>%default_destructor</tt>
-<li><tt>%default_type</tt>
-<li><tt>%destructor</tt>
-<li><tt>%endif</tt>
-<li><tt>%extra_argument</tt>
-<li><tt>%fallback</tt>
-<li><tt>%ifdef</tt>
-<li><tt>%ifndef</tt>
-<li><tt>%include</tt>
-<li><tt>%left</tt>
-<li><tt>%name</tt>
-<li><tt>%nonassoc</tt>
-<li><tt>%parse_accept</tt>
-<li><tt>%parse_failure </tt>
-<li><tt>%right</tt>
-<li><tt>%stack_overflow</tt>
-<li><tt>%stack_size</tt>
-<li><tt>%start_symbol</tt>
-<li><tt>%syntax_error</tt>
-<li><tt>%token_class</tt>
-<li><tt>%token_destructor</tt>
-<li><tt>%token_prefix</tt>
-<li><tt>%token_type</tt>
-<li><tt>%type</tt>
-<li><tt>%wildcard</tt>
+<li><tt><a href='#pcode'>%code</a></tt>
+<li><tt><a href='#default_destructor'>%default_destructor</a></tt>
+<li><tt><a href='#default_type'>%default_type</a></tt>
+<li><tt><a href='#destructor'>%destructor</a></tt>
+<li><tt><a href='#pifdef'>%endif</a></tt>
+<li><tt><a href='#extraarg'>%extra_argument</a></tt>
+<li><tt><a href='#pfallback'>%fallback</a></tt>
+<li><tt><a href='#pifdef'>%ifdef</a></tt>
+<li><tt><a href='#pifdef'>%ifndef</a></tt>
+<li><tt><a href='#pinclude'>%include</a></tt>
+<li><tt><a href='#pleft'>%left</a></tt>
+<li><tt><a href='#pname'>%name</a></tt>
+<li><tt><a href='#pnonassoc'>%nonassoc</a></tt>
+<li><tt><a href='#parse_accept'>%parse_accept</a></tt>
+<li><tt><a href='#parse_failure'>%parse_failure</a></tt>
+<li><tt><a href='#pright'>%right</a></tt>
+<li><tt><a href='#stack_overflow'>%stack_overflow</a></tt>
+<li><tt><a href='#stack_size'>%stack_size</a></tt>
+<li><tt><a href='#start_symbol'>%start_symbol</a></tt>
+<li><tt><a href='#syntax_error'>%syntax_error</a></tt>
+<li><tt><a href='#token_class'>%token_class</a></tt>
+<li><tt><a href='#token_destructor'>%token_destructor</a></tt>
+<li><tt><a href='#token_prefix'>%token_prefix</a></tt>
+<li><tt><a href='#token_type'>%token_type</a></tt>
+<li><tt><a href='#ptype'>%type</a></tt>
+<li><tt><a href='#pwildcard'>%wildcard</a></tt>
</ul>
Each of these directives will be described separately in the
following sections:</p>
@@ -577,43 +581,42 @@ following sections:</p>
<a name='pcode'></a>
<h4>The <tt>%code</tt> directive</h4>
-<p>The %code directive is used to specify addition C code that
+<p>The <tt>%code</tt> directive is used to specify additional C code that
is added to the end of the main output file. This is similar to
-the <a href='#pinclude'>%include</a> directive except that %include
-is inserted at the beginning of the main output file.</p>
+the <tt><a href='#pinclude'>%include</a></tt> directive except that
+<tt>%include</tt> is inserted at the beginning of the main output file.</p>
-<p>%code is typically used to include some action routines or perhaps
+<p><tt>%code</tt> is typically used to include some action routines or perhaps
a tokenizer or even the "main()" function
as part of the output file.</p>
<a name='default_destructor'></a>
<h4>The <tt>%default_destructor</tt> directive</h4>
-<p>The %default_destructor directive specifies a destructor to
+<p>The <tt>%default_destructor</tt> directive specifies a destructor to
use for non-terminals that do not have their own destructor
-specified by a separate %destructor directive. See the documentation
-on the <a name='#destructor'>%destructor</a> directive below for
+specified by a separate <tt>%destructor</tt> directive. See the documentation
+on the <tt><a name='#destructor'>%destructor</a></tt> directive below for
additional information.</p>
-<p>In some grammers, many different non-terminal symbols have the
-same datatype and hence the same destructor. This directive is
-a convenience way to specify the same destructor for all those
+<p>In some grammars, many different non-terminal symbols have the
+same data type and hence the same destructor. This directive is
+a convenient way to specify the same destructor for all those
non-terminals using a single statement.</p>
<a name='default_type'></a>
<h4>The <tt>%default_type</tt> directive</h4>
-<p>The %default_type directive specifies the datatype of non-terminal
-symbols that do no have their own datatype defined using a separate
-<a href='#ptype'>%type</a> directive.
-</p>
+<p>The <tt>%default_type</tt> directive specifies the data type of non-terminal
+symbols that do not have their own data type defined using a separate
+<tt><a href='#ptype'>%type</a></tt> directive.</p>
<a name='destructor'></a>
<h4>The <tt>%destructor</tt> directive</h4>
-<p>The %destructor directive is used to specify a destructor for
+<p>The <tt>%destructor</tt> directive is used to specify a destructor for
a non-terminal symbol.
-(See also the <a href='#token_destructor'>%token_destructor</a>
+(See also the <tt><a href='#token_destructor'>%token_destructor</a></tt>
directive which is used to specify a destructor for terminal symbols.)</p>
<p>A non-terminal's destructor is called to dispose of the
@@ -635,7 +638,7 @@ or other resources held by that non-terminal.</p>
%destructor nt { free($$); }
nt(A) ::= ID NUM. { A = malloc( 100 ); }
</pre>
-This example is a bit contrived but it serves to illustrate how
+This example is a bit contrived, but it serves to illustrate how
destructors work. The example shows a non-terminal named
"nt" that holds values of type "void*". When the rule for
an "nt" reduces, it sets the value of the non-terminal to
@@ -651,17 +654,17 @@ stack, unless the non-terminal is used in a C-code action. If
the non-terminal is used by C-code, then it is assumed that the
C-code will take care of destroying it.
More commonly, the value is used to build some
-larger structure and we don't want to destroy it, which is why
+larger structure, and we don't want to destroy it, which is why
the destructor is not called in this circumstance.</p>
<p>Destructors help avoid memory leaks by automatically freeing
allocated objects when they go out of scope.
To do the same using yacc or bison is much more difficult.</p>
-<a name="extraarg"></a>
+<a name='extraarg'></a>
<h4>The <tt>%extra_argument</tt> directive</h4>
-The %extra_argument directive instructs Lemon to add a 4th parameter
+The <tt>%extra_argument</tt> directive instructs Lemon to add a 4th parameter
to the parameter list of the Parse() function it generates. Lemon
doesn't do anything itself with this extra argument, but it does
make the argument available to C-code action routines, destructors,
@@ -679,61 +682,64 @@ in the most recent call to Parse().</p>
<a name='pfallback'></a>
<h4>The <tt>%fallback</tt> directive</h4>
-<p>The %fallback directive specifies an alternative meaning for one
+<p>The <tt>%fallback</tt> directive specifies an alternative meaning for one
or more tokens. The alternative meaning is tried if the original token
-would have generated a syntax error.
+would have generated a syntax error.</p>
-<p>The %fallback directive was added to support robust parsing of SQL
-syntax in <a href="https://www.sqlite.org/">SQLite</a>.
+<p>The <tt>%fallback</tt> directive was added to support robust parsing of SQL
+syntax in <a href='https://www.sqlite.org/'>SQLite</a>.
The SQL language contains a large assortment of keywords, each of which
appears as a different token to the language parser. SQL contains so
-many keywords, that it can be difficult for programmers to keep up with
+many keywords that it can be difficult for programmers to keep up with
them all. Programmers will, therefore, sometimes mistakenly use an
-obscure language keyword for an identifier. The %fallback directive
+obscure language keyword for an identifier. The <tt>%fallback</tt> directive
provides a mechanism to tell the parser: "If you are unable to parse
-this keyword, try treating it as an identifier instead."
+this keyword, try treating it as an identifier instead."</p>
-<p>The syntax of %fallback is as follows:
+<p>The syntax of <tt>%fallback</tt> is as follows:
<blockquote>
-<tt>%fallback</tt> <i>ID</i> <i>TOKEN...</i> <b>.</b>
-</blockquote>
+<tt>%fallback</tt> <i>ID</i> <i>TOKEN...</i> <b>.</b>
+</blockquote></p>
-<p>In words, the %fallback directive is followed by a list of token names
-terminated by a period. The first token name is the fallback token - the
+<p>In words, the <tt>%fallback</tt> directive is followed by a list of token
+names terminated by a period.
+The first token name is the fallback token &mdash; the
token to which all the other tokens fall back to. The second and subsequent
arguments are tokens which fall back to the token identified by the first
-argument.
+argument.</p>
<a name='pifdef'></a>
-<h4>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives.</h4>
+<h4>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives</h4>
-<p>The %ifdef, %ifndef, and %endif directives are similar to
-#ifdef, #ifndef, and #endif in the C-preprocessor, just not as general.
+<p>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives
+are similar to #ifdef, #ifndef, and #endif in the C-preprocessor,
+just not as general.
Each of these directives must begin at the left margin. No whitespace
-is allowed between the "%" and the directive name.
+is allowed between the "%" and the directive name.</p>
-<p>Grammar text in between "%ifdef MACRO" and the next nested "%endif" is
+<p>Grammar text in between "<tt>%ifdef MACRO</tt>" and the next nested
+"<tt>%endif</tt>" is
ignored unless the "-DMACRO" command-line option is used. Grammar text
-betwen "%ifndef MACRO" and the next nested "%endif" is included except when
-the "-DMACRO" command-line option is used.
+betwen "<tt>%ifndef MACRO</tt>" and the next nested "<tt>%endif</tt>" is
+included except when the "-DMACRO" command-line option is used.</p>
-<p>Note that the argument to %ifdef and %ifndef must be a single
-preprocessor symbol name, not a general expression. There is no "%else"
-directive.
+<p>Note that the argument to <tt>%ifdef</tt> and <tt>%ifndef</tt> must
+be a single preprocessor symbol name, not a general expression.
+There is no "<tt>%else</tt>" directive.</p>
<a name='pinclude'></a>
<h4>The <tt>%include</tt> directive</h4>
-<p>The %include directive specifies C code that is included at the
-top of the generated parser. You can include any text you want --
+<p>The <tt>%include</tt> directive specifies C code that is included at the
+top of the generated parser. You can include any text you want &mdash;
the Lemon parser generator copies it blindly. If you have multiple
-%include directives in your grammar file, their values are concatenated
-so that all %include code ultimately appears near the top of the
-generated parser, in the same order as it appeared in the grammer.</p>
+<tt>%include</tt> directives in your grammar file, their values are concatenated
+so that all <tt>%include</tt> code ultimately appears near the top of the
+generated parser, in the same order as it appeared in the grammar.</p>
-<p>The %include directive is very handy for getting some extra #include
+<p>The <tt>%include</tt> directive is very handy for getting some extra #include
preprocessor statements at the beginning of the generated parser.
For example:</p>
@@ -742,17 +748,19 @@ For example:</p>
</pre></p>
<p>This might be needed, for example, if some of the C actions in the
-grammar call functions that are prototyed in unistd.h.</p>
+grammar call functions that are prototyped in unistd.h.</p>
<a name='pleft'></a>
<h4>The <tt>%left</tt> directive</h4>
-The %left directive is used (along with the <a href='#pright'>%right</a> and
-<a href='#pnonassoc'>%nonassoc</a> directives) to declare precedences of
-terminal symbols. Every terminal symbol whose name appears after
-a %left directive but before the next period (".") is
+The <tt>%left</tt> directive is used (along with the
+<tt><a href='#pright'>%right</a></tt> and
+<tt><a href='#pnonassoc'>%nonassoc</a></tt> directives) to declare
+precedences of terminal symbols.
+Every terminal symbol whose name appears after
+a <tt>%left</tt> directive but before the next period (".") is
given the same left-associative precedence value. Subsequent
-%left directives have higher precedence. For example:</p>
+<tt>%left</tt> directives have higher precedence. For example:</p>
<p><pre>
%left AND.
@@ -763,20 +771,21 @@ given the same left-associative precedence value. Subsequent
%right EXP NOT.
</pre></p>
-<p>Note the period that terminates each %left, %right or %nonassoc
+<p>Note the period that terminates each <tt>%left</tt>,
+<tt>%right</tt> or <tt>%nonassoc</tt>
directive.</p>
<p>LALR(1) grammars can get into a situation where they require
a large amount of stack space if you make heavy use or right-associative
-operators. For this reason, it is recommended that you use %left
-rather than %right whenever possible.</p>
+operators. For this reason, it is recommended that you use <tt>%left</tt>
+rather than <tt>%right</tt> whenever possible.</p>
<a name='pname'></a>
<h4>The <tt>%name</tt> directive</h4>
<p>By default, the functions generated by Lemon all begin with the
five-character string "Parse". You can change this string to something
-different using the %name directive. For instance:</p>
+different using the <tt>%name</tt> directive. For instance:</p>
<p><pre>
%name Abcde
@@ -790,9 +799,8 @@ functions named
<li> AbcdeTrace(), and
<li> Abcde().
</ul>
-The %name directive allows you to generator two or more different
-parsers and link them all into the same executable.
-</p>
+The <tt>%name</tt> directive allows you to generate two or more different
+parsers and link them all into the same executable.</p>
<a name='pnonassoc'></a>
<h4>The <tt>%nonassoc</tt> directive</h4>
@@ -800,12 +808,13 @@ parsers and link them all into the same executable.
<p>This directive is used to assign non-associative precedence to
one or more terminal symbols. See the section on
<a href='#precrules'>precedence rules</a>
-or on the <a href='#pleft'>%left</a> directive for additional information.</p>
+or on the <tt><a href='#pleft'>%left</a></tt> directive
+for additional information.</p>
<a name='parse_accept'></a>
<h4>The <tt>%parse_accept</tt> directive</h4>
-<p>The %parse_accept directive specifies a block of C code that is
+<p>The <tt>%parse_accept</tt> directive specifies a block of C code that is
executed whenever the parser accepts its input string. To "accept"
an input string means that the parser was able to process all tokens
without error.</p>
@@ -821,7 +830,7 @@ without error.</p>
<a name='parse_failure'></a>
<h4>The <tt>%parse_failure</tt> directive</h4>
-<p>The %parse_failure directive specifies a block of C code that
+<p>The <tt>%parse_failure</tt> directive specifies a block of C code that
is executed whenever the parser fails complete. This code is not
executed until the parser has tried and failed to resolve an input
error using is usual error recovery strategy. The routine is
@@ -844,7 +853,7 @@ or on the <a href='#pleft'>%left</a> directive for additional information.</p>
<a name='stack_overflow'></a>
<h4>The <tt>%stack_overflow</tt> directive</h4>
-<p>The %stack_overflow directive specifies a block of C code that
+<p>The <tt>%stack_overflow</tt> directive specifies a block of C code that
is executed if the parser's internal stack ever overflows. Typically
this just prints an error message. After a stack overflow, the parser
will be unable to continue and must be reset.</p>
@@ -857,7 +866,7 @@ will be unable to continue and must be reset.</p>
<p>You can help prevent parser stack overflows by avoiding the use
of right recursion and right-precedence operators in your grammar.
-Use left recursion and and left-precedence operators instead, to
+Use left recursion and and left-precedence operators instead to
encourage rules to reduce sooner and keep the stack size down.
For example, do rules like this:
<pre>
@@ -868,7 +877,7 @@ Not like this:
<pre>
list ::= element list. // right-recursion. Bad!
list ::= .
-</pre>
+</pre></p>
<a name='stack_size'></a>
<h4>The <tt>%stack_size</tt> directive</h4>
@@ -876,7 +885,7 @@ Not like this:
<p>If stack overflow is a problem and you can't resolve the trouble
by using left-recursion, then you might want to increase the size
of the parser's stack using this directive. Put an positive integer
-after the %stack_size directive and Lemon will generate a parse
+after the <tt>%stack_size</tt> directive and Lemon will generate a parse
with a stack of the requested size. The default value is 100.</p>
<p><pre>
@@ -886,25 +895,40 @@ with a stack of the requested size. The default value is 100.</p>
<a name='start_symbol'></a>
<h4>The <tt>%start_symbol</tt> directive</h4>
-<p>By default, the start-symbol for the grammar that Lemon generates
+<p>By default, the start symbol for the grammar that Lemon generates
is the first non-terminal that appears in the grammar file. But you
-can choose a different start-symbol using the %start_symbol directive.</p>
+can choose a different start symbol using the
+<tt>%start_symbol</tt> directive.</p>
<p><pre>
%start_symbol prog
</pre></p>
+<a name='syntax_error'></a>
+<h4>The <tt>%syntax_error</tt> directive</h4>
+
+<p>See <a href='#error_processing'>Error Processing</a>.</p>
+
+<a name='token_class'></a>
+<h4>The <tt>%token_class</tt> directive</h4>
+
+<p>Undocumented. Appears to be related to the MULTITERMINAL concept.
+<a href='http://sqlite.org/src/fdiff?v1=796930d5fc2036c7&v2=624b24c5dc048e09&sbs=0'>Implementation</a>.</p>
+
<a name='token_destructor'></a>
<h4>The <tt>%token_destructor</tt> directive</h4>
-<p>The %destructor directive assigns a destructor to a non-terminal
-symbol. (See the description of the %destructor directive above.)
-This directive does the same thing for all terminal symbols.</p>
+<p>The <tt>%destructor</tt> directive assigns a destructor to a non-terminal
+symbol. (See the description of the
+<tt><a href='%destructor'>%destructor</a></tt> directive above.)
+The <tt>%token_destructor</tt> directive does the same thing
+for all terminal symbols.</p>
<p>Unlike non-terminal symbols which may each have a different data type
for their values, terminals all use the same data type (defined by
-the %token_type directive) and so they use a common destructor. Other
-than that, the token destructor works just like the non-terminal
+the <tt><a href='#token_type'>%token_type</a></tt> directive)
+and so they use a common destructor.
+Other than that, the token destructor works just like the non-terminal
destructors.</p>
<a name='token_prefix'></a>
@@ -913,8 +937,9 @@ destructors.</p>
<p>Lemon generates #defines that assign small integer constants
to each terminal symbol in the grammar. If desired, Lemon will
add a prefix specified by this directive
-to each of the #defines it generates.
-So if the default output of Lemon looked like this:
+to each of the #defines it generates.</p>
+
+<p>So if the default output of Lemon looked like this:
<pre>
#define AND 1
#define MINUS 2
@@ -931,7 +956,7 @@ to cause Lemon to produce these symbols instead:
#define TOKEN_MINUS 2
#define TOKEN_OR 3
#define TOKEN_PLUS 4
-</pre>
+</pre></p>
<a name='token_type'></a><a name='ptype'></a>
<h4>The <tt>%token_type</tt> and <tt>%type</tt> directives</h4>
@@ -952,7 +977,7 @@ token structure. Like this:</p>
is "void*".</p>
<p>Non-terminal symbols can each have their own data types. Typically
-the data type of a non-terminal is a pointer to the root of a parse-tree
+the data type of a non-terminal is a pointer to the root of a parse tree
structure that contains all information about that non-terminal.
For example:</p>
@@ -973,14 +998,15 @@ and able to pay that price, fine. You just need to know.</p>
<a name='pwildcard'></a>
<h4>The <tt>%wildcard</tt> directive</h4>
-<p>The %wildcard directive is followed by a single token name and a
+<p>The <tt>%wildcard</tt> directive is followed by a single token name and a
period. This directive specifies that the identified token should
-match any input token.
+match any input token.</p>
<p>When the generated parser has the choice of matching an input against
the wildcard token and some other token, the other token is always used.
-The wildcard token is only matched if there are no other alternatives.
+The wildcard token is only matched if there are no alternatives.</p>
+<a name='error_processing'></a>
<h3>Error Processing</h3>
<p>After extensive experimentation over several years, it has been
@@ -988,16 +1014,17 @@ discovered that the error recovery strategy used by yacc is about
as good as it gets. And so that is what Lemon uses.</p>
<p>When a Lemon-generated parser encounters a syntax error, it
-first invokes the code specified by the %syntax_error directive, if
+first invokes the code specified by the <tt>%syntax_error</tt> directive, if
any. It then enters its error recovery strategy. The error recovery
strategy is to begin popping the parsers stack until it enters a
state where it is permitted to shift a special non-terminal symbol
named "error". It then shifts this non-terminal and continues
-parsing. But the %syntax_error routine will not be called again
+parsing. The <tt>%syntax_error</tt> routine will not be called again
until at least three new tokens have been successfully shifted.</p>
<p>If the parser pops its stack until the stack is empty, and it still
-is unable to shift the error symbol, then the %parse_failed routine
+is unable to shift the error symbol, then the
+<tt><a href='#parse_failure'>%parse_failure</a></tt> routine
is invoked and the parser resets itself to its start state, ready
to begin parsing a new file. This is what will happen at the very
first syntax error, of course, if there are no instances of the
diff --git a/third_party/sqlite/src/ext/fts5/fts5_vocab.c b/third_party/sqlite/src/ext/fts5/fts5_vocab.c
index 5d72c80..7ac5658 100644
--- a/third_party/sqlite/src/ext/fts5/fts5_vocab.c
+++ b/third_party/sqlite/src/ext/fts5/fts5_vocab.c
@@ -29,6 +29,11 @@
** 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 in the database.
+**
+** instance:
+** CREATE TABLE vocab(term, doc, col, offset, PRIMARY KEY(<all-fields>));
+**
+** One row for each term instance in the database.
*/
@@ -44,7 +49,7 @@ struct Fts5VocabTable {
char *zFts5Db; /* Db containing fts5 table */
sqlite3 *db; /* Database handle */
Fts5Global *pGlobal; /* FTS5 global object for this database */
- int eType; /* FTS5_VOCAB_COL or ROW */
+ int eType; /* FTS5_VOCAB_COL, ROW or INSTANCE */
};
struct Fts5VocabCursor {
@@ -64,16 +69,22 @@ struct Fts5VocabCursor {
i64 *aCnt;
i64 *aDoc;
- /* Output values used by 'row' and 'col' tables */
+ /* Output values used by all tables. */
i64 rowid; /* This table's current rowid value */
Fts5Buffer term; /* Current value of 'term' column */
+
+ /* Output values Used by 'instance' tables only */
+ i64 iInstPos;
+ int iInstOff;
};
-#define FTS5_VOCAB_COL 0
-#define FTS5_VOCAB_ROW 1
+#define FTS5_VOCAB_COL 0
+#define FTS5_VOCAB_ROW 1
+#define FTS5_VOCAB_INSTANCE 2
#define FTS5_VOCAB_COL_SCHEMA "term, col, doc, cnt"
#define FTS5_VOCAB_ROW_SCHEMA "term, doc, cnt"
+#define FTS5_VOCAB_INST_SCHEMA "term, doc, col, offset"
/*
** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
@@ -101,6 +112,9 @@ static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){
if( sqlite3_stricmp(zCopy, "row")==0 ){
*peType = FTS5_VOCAB_ROW;
}else
+ if( sqlite3_stricmp(zCopy, "instance")==0 ){
+ *peType = FTS5_VOCAB_INSTANCE;
+ }else
{
*pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy);
rc = SQLITE_ERROR;
@@ -161,7 +175,8 @@ static int fts5VocabInitVtab(
){
const char *azSchema[] = {
"CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")",
- "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")"
+ "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")",
+ "CREATE TABlE vocab(" FTS5_VOCAB_INST_SCHEMA ")"
};
Fts5VocabTable *pRet = 0;
@@ -235,6 +250,15 @@ static int fts5VocabCreateMethod(
/*
** Implementation of the xBestIndex method.
+**
+** Only constraints of the form:
+**
+** term <= ?
+** term == ?
+** term >= ?
+**
+** are interpreted. Less-than and less-than-or-equal are treated
+** identically, as are greater-than and greater-than-or-equal.
*/
static int fts5VocabBestIndexMethod(
sqlite3_vtab *pUnused,
@@ -378,6 +402,54 @@ static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){
return SQLITE_OK;
}
+static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){
+ int rc = SQLITE_OK;
+
+ if( sqlite3Fts5IterEof(pCsr->pIter) ){
+ pCsr->bEof = 1;
+ }else{
+ const char *zTerm;
+ int nTerm;
+ zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
+ if( pCsr->nLeTerm>=0 ){
+ int nCmp = MIN(nTerm, pCsr->nLeTerm);
+ int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
+ if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){
+ pCsr->bEof = 1;
+ }
+ }
+
+ sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
+ }
+ return rc;
+}
+
+static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
+ int eDetail = pCsr->pConfig->eDetail;
+ int rc = SQLITE_OK;
+ Fts5IndexIter *pIter = pCsr->pIter;
+ i64 *pp = &pCsr->iInstPos;
+ int *po = &pCsr->iInstOff;
+
+ while( eDetail==FTS5_DETAIL_NONE
+ || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp)
+ ){
+ pCsr->iInstPos = 0;
+ pCsr->iInstOff = 0;
+
+ rc = sqlite3Fts5IterNextScan(pCsr->pIter);
+ if( rc==SQLITE_OK ){
+ rc = fts5VocabInstanceNewTerm(pCsr);
+ if( eDetail==FTS5_DETAIL_NONE ) break;
+ }
+ if( rc ){
+ pCsr->bEof = 1;
+ break;
+ }
+ }
+
+ return rc;
+}
/*
** Advance the cursor to the next row in the table.
@@ -390,13 +462,17 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
pCsr->rowid++;
+ if( pTab->eType==FTS5_VOCAB_INSTANCE ){
+ return fts5VocabInstanceNext(pCsr);
+ }
+
if( pTab->eType==FTS5_VOCAB_COL ){
for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
if( pCsr->aDoc[pCsr->iCol] ) break;
}
}
- if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){
+ if( pTab->eType!=FTS5_VOCAB_COL || pCsr->iCol>=nCol ){
if( sqlite3Fts5IterEof(pCsr->pIter) ){
pCsr->bEof = 1;
}else{
@@ -420,22 +496,26 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
while( rc==SQLITE_OK ){
+ int eDetail = pCsr->pConfig->eDetail;
const u8 *pPos; int nPos; /* Position list */
i64 iPos = 0; /* 64-bit position read from poslist */
int iOff = 0; /* Current offset within position list */
pPos = pCsr->pIter->pData;
nPos = pCsr->pIter->nData;
- switch( pCsr->pConfig->eDetail ){
- case FTS5_DETAIL_FULL:
- pPos = pCsr->pIter->pData;
- nPos = pCsr->pIter->nData;
- if( pTab->eType==FTS5_VOCAB_ROW ){
+
+ switch( pTab->eType ){
+ case FTS5_VOCAB_ROW:
+ if( eDetail==FTS5_DETAIL_FULL ){
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
pCsr->aCnt[0]++;
}
- pCsr->aDoc[0]++;
- }else{
+ }
+ pCsr->aDoc[0]++;
+ break;
+
+ case FTS5_VOCAB_COL:
+ if( eDetail==FTS5_DETAIL_FULL ){
int iCol = -1;
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
int ii = FTS5_POS2COLUMN(iPos);
@@ -449,13 +529,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
iCol = ii;
}
}
- }
- break;
-
- case FTS5_DETAIL_COLUMNS:
- if( pTab->eType==FTS5_VOCAB_ROW ){
- pCsr->aDoc[0]++;
- }else{
+ }else if( eDetail==FTS5_DETAIL_COLUMNS ){
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){
assert_nc( iPos>=0 && iPos<nCol );
if( iPos>=nCol ){
@@ -464,18 +538,21 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
}
pCsr->aDoc[iPos]++;
}
+ }else{
+ assert( eDetail==FTS5_DETAIL_NONE );
+ pCsr->aDoc[0]++;
}
break;
default:
- assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE );
- pCsr->aDoc[0]++;
+ assert( pTab->eType==FTS5_VOCAB_INSTANCE );
break;
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IterNextScan(pCsr->pIter);
}
+ if( pTab->eType==FTS5_VOCAB_INSTANCE ) break;
if( rc==SQLITE_OK ){
zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
@@ -505,7 +582,9 @@ static int fts5VocabFilterMethod(
int nUnused, /* Number of elements in apVal */
sqlite3_value **apVal /* Arguments for the indexing scheme */
){
+ Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
+ int eType = pTab->eType;
int rc = SQLITE_OK;
int iVal = 0;
@@ -545,11 +624,16 @@ static int fts5VocabFilterMethod(
}
}
-
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
}
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){
+ rc = fts5VocabInstanceNewTerm(pCsr);
+ }
+ if( rc==SQLITE_OK
+ && !pCsr->bEof
+ && (eType!=FTS5_VOCAB_INSTANCE || pCsr->pConfig->eDetail!=FTS5_DETAIL_NONE)
+ ){
rc = fts5VocabNextMethod(pCursor);
}
@@ -591,13 +675,41 @@ static int fts5VocabColumnMethod(
}else{
iVal = pCsr->aCnt[pCsr->iCol];
}
- }else{
+ }else if( eType==FTS5_VOCAB_ROW ){
assert( iCol==1 || iCol==2 );
if( iCol==1 ){
iVal = pCsr->aDoc[0];
}else{
iVal = pCsr->aCnt[0];
}
+ }else{
+ assert( eType==FTS5_VOCAB_INSTANCE );
+ switch( iCol ){
+ case 1:
+ sqlite3_result_int64(pCtx, pCsr->pIter->iRowid);
+ break;
+ case 2: {
+ int ii = -1;
+ if( eDetail==FTS5_DETAIL_FULL ){
+ ii = FTS5_POS2COLUMN(pCsr->iInstPos);
+ }else if( eDetail==FTS5_DETAIL_COLUMNS ){
+ ii = (int)pCsr->iInstPos;
+ }
+ if( ii>=0 && ii<pCsr->pConfig->nCol ){
+ const char *z = pCsr->pConfig->azCol[ii];
+ sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
+ }
+ break;
+ }
+ default: {
+ assert( iCol==3 );
+ if( eDetail==FTS5_DETAIL_FULL ){
+ int ii = FTS5_POS2OFFSET(pCsr->iInstPos);
+ sqlite3_result_int(pCtx, ii);
+ }
+ break;
+ }
+ }
}
if( iVal>0 ) sqlite3_result_int64(pCtx, iVal);
diff --git a/third_party/sqlite/src/ext/fts5/test/fts5connect.test b/third_party/sqlite/src/ext/fts5/test/fts5connect.test
new file mode 100644
index 0000000..d48a428
--- /dev/null
+++ b/third_party/sqlite/src/ext/fts5/test/fts5connect.test
@@ -0,0 +1,247 @@
+# 2017 August 17
+#
+# 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.
+#
+#*************************************************************************
+#
+
+
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5connect
+
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+#-------------------------------------------------------------------------
+# The tests in this file test the outcome of a schema-reset happening
+# within the xConnect() method of an FTS5 table. At one point this
+# was causing a problem in SQLite. Each test proceeds as follows:
+#
+# 1. Connection [db] opens the db and reads from some unrelated, non-FTS5
+# table causing SQLite to load the db schema into memory.
+#
+# 2. Connection [db2] opens the db and modifies the db schema.
+#
+# 3. Connection [db] reads or writes an existing fts5 table. That the
+# schema has been modified is detected inside the fts5 xConnect()
+# callback that is invoked by sqlite3_prepare().
+#
+# 4. Verify that the statement in 3 has worked. SQLite should detect
+# that the schema has changed and successfully prepare the
+# statement against the new schema.
+#
+# Test plan:
+#
+# 1.*: Trigger the xConnect()/schema-reset using statements executed
+# directly against an FTS5 table.
+#
+# 2.*: Using various statements executed by various BEFORE triggers.
+#
+# 3.*: Using various statements executed by various AFTER triggers.
+#
+# 4.*: Using various statements executed by various INSTEAD OF triggers.
+#
+
+
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE ft1 USING fts5(a, b);
+ CREATE TABLE abc(x INTEGER PRIMARY KEY);
+ CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b);
+
+ INSERT INTO ft1 VALUES('one', 'two');
+ INSERT INTO ft1 VALUES('three', 'four');
+}
+
+foreach {tn sql res} {
+ 1 "SELECT * FROM ft1" {one two three four}
+ 2 "REPLACE INTO ft1(rowid, a, b) VALUES(1, 'five', 'six')" {}
+ 3 "SELECT * FROM ft1" {five six three four}
+ 4 "INSERT INTO ft1 VALUES('seven', 'eight')" {}
+ 5 "SELECT * FROM ft1" {five six three four seven eight}
+ 6 "DELETE FROM ft1 WHERE rowid=2" {}
+ 7 "UPDATE ft1 SET b='nine' WHERE rowid=1" {}
+ 8 "SELECT * FROM ft1" {five nine seven eight}
+} {
+
+ catch { db close }
+ catch { db2 close }
+ sqlite3 db test.db
+ sqlite3 db2 test.db
+
+ do_test 1.$tn.1 {
+ db eval { INSERT INTO abc DEFAULT VALUES }
+ db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable }
+ } {}
+
+ do_execsql_test 1.$tn.2 $sql $res
+
+ do_execsql_test 1.$tn.3 {
+ INSERT INTO ft1(ft1) VALUES('integrity-check');
+ }
+}
+
+do_execsql_test 2.0 {
+ CREATE VIRTUAL TABLE ft2 USING fts5(a, b);
+ CREATE TABLE t2(a, b);
+ CREATE TABLE log(txt);
+
+ CREATE TRIGGER t2_ai AFTER INSERT ON t2 BEGIN
+ INSERT INTO ft2(rowid, a, b) VALUES(new.rowid, new.a, new.b);
+ INSERT INTO log VALUES('insert');
+ END;
+
+ CREATE TRIGGER t2_ad AFTER DELETE ON t2 BEGIN
+ DELETE FROM ft2 WHERE rowid = old.rowid;
+ INSERT INTO log VALUES('delete');
+ END;
+
+ CREATE TRIGGER t2_au AFTER UPDATE ON t2 BEGIN
+ UPDATE ft2 SET a=new.a, b=new.b WHERE rowid=new.rowid;
+ INSERT INTO log VALUES('update');
+ END;
+
+ INSERT INTO t2 VALUES('one', 'two');
+ INSERT INTO t2 VALUES('three', 'four');
+}
+
+foreach {tn sql res} {
+ 1 "SELECT * FROM t2" {one two three four}
+ 2 "REPLACE INTO t2(rowid, a, b) VALUES(1, 'five', 'six')" {}
+ 3 "SELECT * FROM ft2" {five six three four}
+ 4 "INSERT INTO t2 VALUES('seven', 'eight')" {}
+ 5 "SELECT * FROM ft2" {five six three four seven eight}
+ 6 "DELETE FROM t2 WHERE rowid=2" {}
+ 7 "UPDATE t2 SET b='nine' WHERE rowid=1" {}
+ 8 "SELECT * FROM ft2" {five nine seven eight}
+} {
+
+ catch { db close }
+ catch { db2 close }
+ sqlite3 db test.db
+ sqlite3 db2 test.db
+
+ do_test 2.$tn.1 {
+ db eval { INSERT INTO abc DEFAULT VALUES }
+ db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable }
+ } {}
+
+ do_execsql_test 2.$tn.2 $sql $res
+
+ do_execsql_test 2.$tn.3 {
+ INSERT INTO ft2(ft2) VALUES('integrity-check');
+ }
+}
+
+do_execsql_test 3.0 {
+ CREATE VIRTUAL TABLE ft3 USING fts5(a, b);
+ CREATE TABLE t3(a, b);
+
+ CREATE TRIGGER t3_ai BEFORE INSERT ON t3 BEGIN
+ INSERT INTO ft3(rowid, a, b) VALUES(new.rowid, new.a, new.b);
+ INSERT INTO log VALUES('insert');
+ END;
+
+ CREATE TRIGGER t3_ad BEFORE DELETE ON t3 BEGIN
+ DELETE FROM ft3 WHERE rowid = old.rowid;
+ INSERT INTO log VALUES('delete');
+ END;
+
+ CREATE TRIGGER t3_au BEFORE UPDATE ON t3 BEGIN
+ UPDATE ft3 SET a=new.a, b=new.b WHERE rowid=new.rowid;
+ INSERT INTO log VALUES('update');
+ END;
+
+ INSERT INTO t3(rowid, a, b) VALUES(1, 'one', 'two');
+ INSERT INTO t3(rowid, a, b) VALUES(2, 'three', 'four');
+}
+
+foreach {tn sql res} {
+ 1 "SELECT * FROM t3" {one two three four}
+ 2 "REPLACE INTO t3(rowid, a, b) VALUES(1, 'five', 'six')" {}
+ 3 "SELECT * FROM ft3" {five six three four}
+ 4 "INSERT INTO t3(rowid, a, b) VALUES(3, 'seven', 'eight')" {}
+ 5 "SELECT * FROM ft3" {five six three four seven eight}
+ 6 "DELETE FROM t3 WHERE rowid=2" {}
+ 7 "UPDATE t3 SET b='nine' WHERE rowid=1" {}
+ 8 "SELECT * FROM ft3" {five nine seven eight}
+} {
+
+ catch { db close }
+ catch { db2 close }
+ sqlite3 db test.db
+ sqlite3 db2 test.db
+
+ do_test 3.$tn.1 {
+ db eval { INSERT INTO abc DEFAULT VALUES }
+ db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable }
+ } {}
+
+ do_execsql_test 3.$tn.2 $sql $res
+
+ do_execsql_test 3.$tn.3 {
+ INSERT INTO ft3(ft3) VALUES('integrity-check');
+ }
+}
+
+do_execsql_test 4.0 {
+ CREATE VIRTUAL TABLE ft4 USING fts5(a, b);
+ CREATE VIEW v4 AS SELECT rowid, * FROM ft4;
+
+ CREATE TRIGGER t4_ai INSTEAD OF INSERT ON v4 BEGIN
+ INSERT INTO ft4(rowid, a, b) VALUES(new.rowid, new.a, new.b);
+ INSERT INTO log VALUES('insert');
+ END;
+
+ CREATE TRIGGER t4_ad INSTEAD OF DELETE ON v4 BEGIN
+ DELETE FROM ft4 WHERE rowid = old.rowid;
+ INSERT INTO log VALUES('delete');
+ END;
+
+ CREATE TRIGGER t4_au INSTEAD OF UPDATE ON v4 BEGIN
+ UPDATE ft4 SET a=new.a, b=new.b WHERE rowid=new.rowid;
+ INSERT INTO log VALUES('update');
+ END;
+
+ INSERT INTO ft4(rowid, a, b) VALUES(1, 'one', 'two');
+ INSERT INTO ft4(rowid, a, b) VALUES(2, 'three', 'four');
+}
+
+foreach {tn sql res} {
+ 1 "SELECT * FROM ft4" {one two three four}
+ 2 "REPLACE INTO v4(rowid, a, b) VALUES(1, 'five', 'six')" {}
+ 3 "SELECT * FROM ft4" {five six three four}
+ 4 "INSERT INTO v4(rowid, a, b) VALUES(3, 'seven', 'eight')" {}
+ 5 "SELECT * FROM ft4" {five six three four seven eight}
+ 6 "DELETE FROM v4 WHERE rowid=2" {}
+ 7 "UPDATE v4 SET b='nine' WHERE rowid=1" {}
+ 8 "SELECT * FROM ft4" {five nine seven eight}
+} {
+
+ catch { db close }
+ catch { db2 close }
+ sqlite3 db test.db
+ sqlite3 db2 test.db
+
+ do_test 4.$tn.1 {
+ db eval { INSERT INTO abc DEFAULT VALUES }
+ db2 eval { CREATE TABLE newtable(x,y); DROP TABLE newtable }
+ } {}
+
+ do_execsql_test 4.$tn.2 $sql $res
+
+ do_execsql_test 4.$tn.3 {
+ INSERT INTO ft3(ft3) VALUES('integrity-check');
+ }
+}
+
+finish_test
+
diff --git a/third_party/sqlite/src/ext/fts5/test/fts5vocab2.test b/third_party/sqlite/src/ext/fts5/test/fts5vocab2.test
new file mode 100644
index 0000000..4a0a1f4
--- /dev/null
+++ b/third_party/sqlite/src/ext/fts5/test/fts5vocab2.test
@@ -0,0 +1,209 @@
+# 2017 August 10
+#
+# 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.
+#
+#***********************************************************************
+#
+# The tests in this file focus on testing the fts5vocab module.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5vocab
+
+# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(a, b);
+ CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance);
+
+ INSERT INTO t1 VALUES('one two', 'two three');
+ INSERT INTO t1 VALUES('three four', 'four five five five');
+}
+
+do_execsql_test 1.1 {
+ SELECT * FROM v1;
+} {
+ five 2 b 1
+ five 2 b 2
+ five 2 b 3
+ four 2 a 1
+ four 2 b 0
+ one 1 a 0
+ three 1 b 1
+ three 2 a 0
+ two 1 a 1
+ two 1 b 0
+}
+
+do_execsql_test 1.2 {
+ SELECT * FROM v1 WHERE term='three';
+} {
+ three 1 b 1
+ three 2 a 0
+}
+
+do_execsql_test 1.3 {
+ BEGIN;
+ DELETE FROM t1 WHERE rowid=2;
+ SELECT * FROM v1;
+ ROLLBACK;
+} {
+ one 1 a 0
+ three 1 b 1
+ two 1 a 1
+ two 1 b 0
+}
+
+do_execsql_test 1.4 {
+ BEGIN;
+ DELETE FROM t1 WHERE rowid=1;
+ SELECT * FROM v1;
+ ROLLBACK;
+} {
+ five 2 b 1
+ five 2 b 2
+ five 2 b 3
+ four 2 a 1
+ four 2 b 0
+ three 2 a 0
+}
+
+do_execsql_test 1.5 {
+ DELETE FROM t1;
+ SELECT * FROM v1;
+} {
+}
+
+#-------------------------------------------------------------------------
+#
+do_execsql_test 2.0 {
+ DROP TABLE IF EXISTS t1;
+ DROP TABLE IF EXISTS v1;
+
+ CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=column);
+ CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance);
+
+ INSERT INTO t1 VALUES('one two', 'two three');
+ INSERT INTO t1 VALUES('three four', 'four five five five');
+}
+
+do_execsql_test 2.1 {
+ SELECT * FROM v1;
+} {
+ five 2 b {}
+ four 2 a {}
+ four 2 b {}
+ one 1 a {}
+ three 1 b {}
+ three 2 a {}
+ two 1 a {}
+ two 1 b {}
+}
+
+do_execsql_test 2.2 {
+ SELECT * FROM v1 WHERE term='three';
+} {
+ three 1 b {}
+ three 2 a {}
+}
+
+do_execsql_test 2.3 {
+ BEGIN;
+ DELETE FROM t1 WHERE rowid=2;
+ SELECT * FROM v1;
+ ROLLBACK;
+} {
+ one 1 a {}
+ three 1 b {}
+ two 1 a {}
+ two 1 b {}
+}
+
+do_execsql_test 2.4 {
+ BEGIN;
+ DELETE FROM t1 WHERE rowid=1;
+ SELECT * FROM v1;
+ ROLLBACK;
+} {
+ five 2 b {}
+ four 2 a {}
+ four 2 b {}
+ three 2 a {}
+}
+
+do_execsql_test 2.5 {
+ DELETE FROM t1;
+ SELECT * FROM v1;
+} {
+}
+
+#-------------------------------------------------------------------------
+#
+do_execsql_test 3.0 {
+ DROP TABLE IF EXISTS t1;
+ DROP TABLE IF EXISTS v1;
+
+ CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=none);
+ CREATE VIRTUAL TABLE v1 USING fts5vocab(t1, instance);
+
+ INSERT INTO t1 VALUES('one two', 'two three');
+ INSERT INTO t1 VALUES('three four', 'four five five five');
+}
+
+do_execsql_test 3.1 {
+ SELECT * FROM v1;
+} {
+ five 2 {} {}
+ four 2 {} {}
+ one 1 {} {}
+ three 1 {} {}
+ three 2 {} {}
+ two 1 {} {}
+}
+
+do_execsql_test 3.2 {
+ SELECT * FROM v1 WHERE term='three';
+} {
+ three 1 {} {}
+ three 2 {} {}
+}
+
+do_execsql_test 3.3 {
+ BEGIN;
+ DELETE FROM t1 WHERE rowid=2;
+ SELECT * FROM v1;
+ ROLLBACK;
+} {
+ one 1 {} {}
+ three 1 {} {}
+ two 1 {} {}
+}
+
+do_execsql_test 3.4 {
+ BEGIN;
+ DELETE FROM t1 WHERE rowid=1;
+ SELECT * FROM v1;
+ ROLLBACK;
+} {
+ five 2 {} {}
+ four 2 {} {}
+ three 2 {} {}
+}
+
+do_execsql_test 3.5 {
+ DELETE FROM t1;
+ SELECT * FROM v1;
+} {
+}
+
+finish_test
+
diff --git a/third_party/sqlite/src/ext/lsm1/lsm_shared.c b/third_party/sqlite/src/ext/lsm1/lsm_shared.c
index 95a866d..f8e2adb 100644
--- a/third_party/sqlite/src/ext/lsm1/lsm_shared.c
+++ b/third_party/sqlite/src/ext/lsm1/lsm_shared.c
@@ -340,9 +340,6 @@ static int doDbConnect(lsm_db *pDb){
/* Obtain a pointer to the shared-memory header */
assert( pDb->pShmhdr==0 );
assert( pDb->bReadonly==0 );
- rc = lsmShmCacheChunks(pDb, 1);
- if( rc!=LSM_OK ) return rc;
- pDb->pShmhdr = (ShmHeader *)pDb->apShm[0];
/* Block for an exclusive lock on DMS1. This lock serializes all calls
** to doDbConnect() and doDbDisconnect() across all processes. */
@@ -353,10 +350,11 @@ static int doDbConnect(lsm_db *pDb){
nUs = nUs * 2;
if( nUs>nUsMax ) nUs = nUsMax;
}
- if( rc!=LSM_OK ){
- pDb->pShmhdr = 0;
- return rc;
+ if( rc==LSM_OK ){
+ rc = lsmShmCacheChunks(pDb, 1);
}
+ if( rc!=LSM_OK ) return rc;
+ pDb->pShmhdr = (ShmHeader *)pDb->apShm[0];
/* Try an exclusive lock on DMS2/DMS3. If successful, this is the first
** and only connection to the database. In this case initialize the
diff --git a/third_party/sqlite/src/ext/lsm1/lsm_vtab.c b/third_party/sqlite/src/ext/lsm1/lsm_vtab.c
index da6ef6f..8a2cc96 100644
--- a/third_party/sqlite/src/ext/lsm1/lsm_vtab.c
+++ b/third_party/sqlite/src/ext/lsm1/lsm_vtab.c
@@ -10,8 +10,82 @@
**
*************************************************************************
**
-** This file implements a simple virtual table wrapper around the LSM
+** This file implements a virtual table for SQLite3 around the LSM
** storage engine from SQLite4.
+**
+** USAGE
+**
+** CREATE VIRTUAL TABLE demo USING lsm1(filename,key,keytype,value1,...);
+**
+** The filename parameter is the name of the LSM database file, which is
+** separate and distinct from the SQLite3 database file.
+**
+** The keytype must be one of: UINT, TEXT, BLOB. All keys must be of that
+** one type. "UINT" means unsigned integer. The values may be of any
+** SQLite datatype: BLOB, TEXT, INTEGER, FLOAT, or NULL.
+**
+** The virtual table contains read-only hidden columns:
+**
+** lsm1_key A BLOB which is the raw LSM key. If the "keytype"
+** is BLOB or TEXT then this column is exactly the
+** same as the key. For the UINT keytype, this column
+** will be a variable-length integer encoding of the key.
+**
+** lsm1_value A BLOB which is the raw LSM value. All of the value
+** columns are packed into this BLOB using the encoding
+** described below.
+**
+** Attempts to write values into the lsm1_key and lsm1_value columns are
+** silently ignored.
+**
+** EXAMPLE
+**
+** The virtual table declared this way:
+**
+** CREATE VIRTUAL TABLE demo2 USING lsm1('x.lsm',id,UINT,a,b,c,d);
+**
+** Results in a new virtual table named "demo2" that acts as if it has
+** the following schema:
+**
+** CREATE TABLE demo2(
+** id UINT PRIMARY KEY ON CONFLICT REPLACE,
+** a ANY,
+** b ANY,
+** c ANY,
+** d ANY,
+** lsm1_key BLOB HIDDEN,
+** lsm1_value BLOB HIDDEN
+** ) WITHOUT ROWID;
+**
+**
+**
+** INTERNALS
+**
+** The key encoding for BLOB and TEXT is just a copy of the blob or text.
+** UTF-8 is used for text. The key encoding for UINT is the variable-length
+** integer format at https://sqlite.org/src4/doc/trunk/www/varint.wiki.
+**
+** The values are encoded as a single blob (since that is what lsm stores as
+** its content). There is a "type integer" followed by "content" for each
+** value, alternating back and forth. The content might be empty.
+**
+** TYPE1 CONTENT1 TYPE2 CONTENT2 TYPE3 CONTENT3 ....
+**
+** Each "type integer" is encoded as a variable-length integer in the
+** format of the link above. Let the type integer be T. The actual
+** datatype is an integer 0-5 equal to T%6. Values 1 through 5 correspond
+** to SQLITE_INTEGER through SQLITE_NULL. The size of the content in bytes
+** is T/6. Type value 0 means that the value is an integer whose actual
+** values is T/6 and there is no content. The type-value-0 integer format
+** only works for integers in the range of 0 through 40.
+**
+** There is no content for NULL or type-0 integers. For BLOB and TEXT
+** values, the content is the blob data or the UTF-8 text data. For
+** non-negative integers X, the content is a variable-length integer X*2.
+** For negative integers Y, the content is varaible-length integer (1-Y)*2+1.
+** For FLOAT values, the content is the IEEE754 floating point value in
+** native byte-order. This means that FLOAT values will be corrupted when
+** database file is moved between big-endian and little-endian machines.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
@@ -22,14 +96,19 @@ SQLITE_EXTENSION_INIT1
/* Forward declaration of subclasses of virtual table objects */
typedef struct lsm1_vtab lsm1_vtab;
typedef struct lsm1_cursor lsm1_cursor;
+typedef struct lsm1_vblob lsm1_vblob;
/* Primitive types */
typedef unsigned char u8;
+typedef unsigned int u32;
+typedef sqlite3_uint64 u64;
/* An open connection to an LSM table */
struct lsm1_vtab {
sqlite3_vtab base; /* Base class - must be first */
lsm_db *pDb; /* Open connection to the LSM table */
+ u8 keyType; /* SQLITE_BLOB, _TEXT, or _INTEGER */
+ u32 nVal; /* Number of value columns */
};
@@ -43,8 +122,82 @@ struct lsm1_cursor {
u8 isDesc; /* 0: scan forward. 1: scan reverse */
u8 atEof; /* True if the scan is complete */
u8 bUnique; /* True if no more than one row of output */
+ u8 *zData; /* Content of the current row */
+ u32 nData; /* Number of bytes in the current row */
+ u8 *aeType; /* Types for all column values */
+ u32 *aiOfst; /* Offsets to the various fields */
+ u32 *aiLen; /* Length of each field */
+ u8 *pKey2; /* Loop termination key, or NULL */
+ u32 nKey2; /* Length of the loop termination key */
};
+/* An extensible buffer object.
+**
+** Content can be appended. Space to hold new content is automatically
+** allocated.
+*/
+struct lsm1_vblob {
+ u8 *a; /* Space to hold content, from sqlite3_malloc64() */
+ u64 n; /* Bytes of space used */
+ u64 nAlloc; /* Bytes of space allocated */
+ u8 errNoMem; /* True if a memory allocation error has been seen */
+};
+
+#if defined(__GNUC__)
+# define LSM1_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER) && _MSC_VER>=1310
+# define LSM1_NOINLINE __declspec(noinline)
+#else
+# define LSM1_NOINLINE
+#endif
+
+
+/* Increase the available space in the vblob object so that it can hold
+** at least N more bytes. Return the number of errors.
+*/
+static int lsm1VblobEnlarge(lsm1_vblob *p, u32 N){
+ if( p->n+N>p->nAlloc ){
+ if( p->errNoMem ) return 1;
+ p->nAlloc += N + (p->nAlloc ? p->nAlloc : N);
+ p->a = sqlite3_realloc64(p->a, p->nAlloc);
+ if( p->a==0 ){
+ p->n = 0;
+ p->nAlloc = 0;
+ p->errNoMem = 1;
+ return 1;
+ }
+ p->nAlloc = sqlite3_msize(p->a);
+ }
+ return 0;
+}
+
+/* Append N bytes to a vblob after first enlarging it */
+static LSM1_NOINLINE void lsm1VblobEnlargeAndAppend(
+ lsm1_vblob *p,
+ const u8 *pData,
+ u32 N
+){
+ if( p->n+N>p->nAlloc && lsm1VblobEnlarge(p, N) ) return;
+ memcpy(p->a+p->n, pData, N);
+ p->n += N;
+}
+
+/* Append N bytes to a vblob */
+static void lsm1VblobAppend(lsm1_vblob *p, const u8 *pData, u32 N){
+ sqlite3_int64 n = p->n;
+ if( n+N>p->nAlloc ){
+ lsm1VblobEnlargeAndAppend(p, pData, N);
+ }else{
+ p->n += N;
+ memcpy(p->a+n, pData, N);
+ }
+}
+
+/* append text to a vblob */
+static void lsm1VblobAppendText(lsm1_vblob *p, const char *z){
+ lsm1VblobAppend(p, (u8*)z, (u32)strlen(z));
+}
+
/* Dequote the string */
static void lsm1Dequote(char *z){
int j;
@@ -76,9 +229,28 @@ static int lsm1Connect(
lsm1_vtab *pNew;
int rc;
char *zFilename;
+ u8 keyType = 0;
+ int i;
+ lsm1_vblob sql;
+ static const char *azTypes[] = { "UINT", "TEXT", "BLOB" };
+ static const u8 aeTypes[] = { SQLITE_INTEGER, SQLITE_TEXT, SQLITE_BLOB };
+ static const char *azArgName[] = {"filename", "key", "key type", "value1" };
- if( argc!=4 || argv[3]==0 || argv[3][0]==0 ){
- *pzErr = sqlite3_mprintf("filename argument missing");
+ for(i=0; i<sizeof(azArgName)/sizeof(azArgName[0]); i++){
+ if( argc<i+4 || argv[i+3]==0 || argv[i+3][0]==0 ){
+ *pzErr = sqlite3_mprintf("%s (%r) argument missing",
+ azArgName[i], i+1);
+ return SQLITE_ERROR;
+ }
+ }
+ for(i=0; i<sizeof(azTypes)/sizeof(azTypes[0]); i++){
+ if( sqlite3_stricmp(azTypes[i],argv[5])==0 ){
+ keyType = aeTypes[i];
+ break;
+ }
+ }
+ if( keyType==0 ){
+ *pzErr = sqlite3_mprintf("key type should be INT, TEXT, or BLOB");
return SQLITE_ERROR;
}
*ppVtab = sqlite3_malloc( sizeof(*pNew) );
@@ -87,6 +259,7 @@ static int lsm1Connect(
return SQLITE_NOMEM;
}
memset(pNew, 0, sizeof(*pNew));
+ pNew->keyType = keyType;
rc = lsm_new(0, &pNew->pDb);
if( rc ){
*pzErr = sqlite3_mprintf("lsm_new failed with error code %d", rc);
@@ -103,22 +276,29 @@ static int lsm1Connect(
goto connect_failed;
}
-/* Column numbers */
-#define LSM1_COLUMN_KEY 0
-#define LSM1_COLUMN_BLOBKEY 1
-#define LSM1_COLUMN_VALUE 2
-#define LSM1_COLUMN_BLOBVALUE 3
-#define LSM1_COLUMN_COMMAND 4
-
- rc = sqlite3_declare_vtab(db,
- "CREATE TABLE x("
- " key," /* The primary key. Any non-NULL */
- " blobkey," /* Pure BLOB primary key */
- " value," /* The value associated with key. Any non-NULL */
- " blobvalue," /* Pure BLOB value */
- " command hidden" /* Insert here for control operations */
- ");"
- );
+ memset(&sql, 0, sizeof(sql));
+ lsm1VblobAppendText(&sql, "CREATE TABLE x(");
+ lsm1VblobAppendText(&sql, argv[4]);
+ lsm1VblobAppendText(&sql, " ");
+ lsm1VblobAppendText(&sql, argv[5]);
+ lsm1VblobAppendText(&sql, " PRIMARY KEY");
+ for(i=6; i<argc; i++){
+ lsm1VblobAppendText(&sql, ", ");
+ lsm1VblobAppendText(&sql, argv[i]);
+ pNew->nVal++;
+ }
+ lsm1VblobAppendText(&sql,
+ ", lsm1_command HIDDEN"
+ ", lsm1_key HIDDEN"
+ ", lsm1_value HIDDEN) WITHOUT ROWID");
+ lsm1VblobAppend(&sql, (u8*)"", 1);
+ if( sql.errNoMem ){
+ rc = SQLITE_NOMEM;
+ goto connect_failed;
+ }
+ rc = sqlite3_declare_vtab(db, (const char*)sql.a);
+ sqlite3_free(sql.a);
+
connect_failed:
if( rc!=SQLITE_OK ){
if( pNew ){
@@ -147,9 +327,13 @@ static int lsm1Open(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){
lsm1_vtab *p = (lsm1_vtab*)pVtab;
lsm1_cursor *pCur;
int rc;
- pCur = sqlite3_malloc( sizeof(*pCur) );
+ pCur = sqlite3_malloc64( sizeof(*pCur)
+ + p->nVal*(sizeof(pCur->aiOfst)+sizeof(pCur->aiLen)+1) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
+ pCur->aiOfst = (u32*)&pCur[1];
+ pCur->aiLen = &pCur->aiOfst[p->nVal];
+ pCur->aeType = (u8*)&pCur->aiLen[p->nVal];
*ppCursor = &pCur->base;
rc = lsm_csr_open(p->pDb, &pCur->pLsmCur);
if( rc==LSM_OK ){
@@ -167,6 +351,7 @@ static int lsm1Open(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){
*/
static int lsm1Close(sqlite3_vtab_cursor *cur){
lsm1_cursor *pCur = (lsm1_cursor*)cur;
+ sqlite3_free(pCur->pKey2);
lsm_csr_close(pCur->pLsmCur);
sqlite3_free(pCur);
return SQLITE_OK;
@@ -190,6 +375,21 @@ static int lsm1Next(sqlite3_vtab_cursor *cur){
if( rc==LSM_OK && lsm_csr_valid(pCur->pLsmCur)==0 ){
pCur->atEof = 1;
}
+ if( pCur->pKey2 && pCur->atEof==0 ){
+ const u8 *pVal;
+ u32 nVal;
+ assert( pCur->isDesc==0 );
+ rc = lsm_csr_key(pCur->pLsmCur, (const void**)&pVal, (int*)&nVal);
+ if( rc==LSM_OK ){
+ u32 len = pCur->nKey2;
+ int c;
+ if( len>nVal ) len = nVal;
+ c = memcmp(pVal, pCur->pKey2, len);
+ if( c==0 ) c = nVal - pCur->nKey2;
+ if( c>0 ) pCur->atEof = 1;
+ }
+ }
+ pCur->zData = 0;
}
return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR;
}
@@ -295,6 +495,14 @@ static int lsm1PutVarint64(unsigned char *z, sqlite3_uint64 x){
return 9;
}
+/* Append non-negative integer x as a variable-length integer.
+*/
+static void lsm1VblobAppendVarint(lsm1_vblob *p, sqlite3_uint64 x){
+ sqlite3_int64 n = p->n;
+ if( n+9>p->nAlloc && lsm1VblobEnlarge(p, 9) ) return;
+ p->n += lsm1PutVarint64(p->a+p->n, x);
+}
+
/*
** Decode the varint in the first n bytes z[]. Write the integer value
** into *pResult and return the number of bytes in the varint.
@@ -349,69 +557,74 @@ static int lsm1GetVarint64(
return 9;
}
-/*
-** Generate a key encoding for pValue such that all keys compare in
-** lexicographical order. Return an SQLite error code or SQLITE_OK.
+/* Encoded a signed integer as a varint. Numbers close to zero uses fewer
+** bytes than numbers far away from zero. However, the result is not in
+** lexicographical order.
**
-** The key encoding is *pnKey bytes in length written into *ppKey.
-** Space to hold the key is taken from pSpace if sufficient, or else
-** from sqlite3_malloc(). The caller is responsible for freeing malloced
-** space.
+** Encoding: Non-negative integer X is encoding as an unsigned
+** varint X*2. Negative integer Y is encoding as an unsigned
+** varint (1-Y)*2 + 1.
*/
-static int lsm1EncodeKey(
- sqlite3_value *pValue, /* Value to be encoded */
- unsigned char **ppKey, /* Write the encoding here */
- int *pnKey, /* Write the size of the encoding here */
- unsigned char *pSpace, /* Use this space if it is large enough */
- int nSpace /* Size of pSpace[] */
+static int lsm1PutSignedVarint64(u8 *z, sqlite3_int64 v){
+ sqlite3_uint64 u;
+ if( v>=0 ){
+ u = (sqlite3_uint64)v;
+ return lsm1PutVarint64(z, u*2);
+ }else{
+ u = (sqlite3_uint64)(-1-v);
+ return lsm1PutVarint64(z, u*2+1);
+ }
+}
+
+/* Decoded a signed varint. */
+static int lsm1GetSignedVarint64(
+ const unsigned char *z,
+ int n,
+ sqlite3_int64 *pResult
){
- int eType = sqlite3_value_type(pValue);
- *ppKey = 0;
- *pnKey = 0;
- assert( nSpace>=32 );
- switch( eType ){
- default: {
- return SQLITE_ERROR; /* We cannot handle NULL keys */
- }
- case SQLITE_BLOB:
- case SQLITE_TEXT: {
- int nVal = sqlite3_value_bytes(pValue);
- const void *pVal;
- if( eType==SQLITE_BLOB ){
- eType = LSM1_TYPE_BLOB;
- pVal = sqlite3_value_blob(pValue);
- }else{
- eType = LSM1_TYPE_TEXT;
- pVal = (const void*)sqlite3_value_text(pValue);
- if( pVal==0 ) return SQLITE_NOMEM;
- }
- if( nVal+1>nSpace ){
- pSpace = sqlite3_malloc( nVal+1 );
- if( pSpace==0 ) return SQLITE_NOMEM;
- }
- pSpace[0] = (unsigned char)eType;
- memcpy(&pSpace[1], pVal, nVal);
- *ppKey = pSpace;
- *pnKey = nVal+1;
- break;
- }
- case SQLITE_INTEGER: {
- sqlite3_int64 iVal = sqlite3_value_int64(pValue);
- sqlite3_uint64 uVal;
- if( iVal<0 ){
- if( iVal==0xffffffffffffffffLL ) return SQLITE_ERROR;
- uVal = *(sqlite3_uint64*)&iVal;
- eType = LSM1_TYPE_NEGATIVE;
- }else{
- uVal = iVal;
- eType = LSM1_TYPE_POSITIVE;
- }
- pSpace[0] = (unsigned char)eType;
- *ppKey = pSpace;
- *pnKey = 1 + lsm1PutVarint64(&pSpace[1], uVal);
+ sqlite3_uint64 u = 0;
+ n = lsm1GetVarint64(z, n, &u);
+ if( u&1 ){
+ *pResult = -1 - (sqlite3_int64)(u>>1);
+ }else{
+ *pResult = (sqlite3_int64)(u>>1);
+ }
+ return n;
+}
+
+
+/*
+** Read the value part of the key-value pair and decode it into columns.
+*/
+static int lsm1DecodeValues(lsm1_cursor *pCur){
+ lsm1_vtab *pTab = (lsm1_vtab*)(pCur->base.pVtab);
+ int i, n;
+ int rc;
+ u8 eType;
+ sqlite3_uint64 v;
+
+ if( pCur->zData ) return 1;
+ rc = lsm_csr_value(pCur->pLsmCur, (const void**)&pCur->zData,
+ (int*)&pCur->nData);
+ if( rc ) return 0;
+ for(i=n=0; i<pTab->nVal; i++){
+ v = 0;
+ n += lsm1GetVarint64(pCur->zData+n, pCur->nData-n, &v);
+ pCur->aeType[i] = eType = (u8)(v%6);
+ if( eType==0 ){
+ pCur->aiOfst[i] = (u32)(v/6);
+ pCur->aiLen[i] = 0;
+ }else{
+ pCur->aiOfst[i] = n;
+ n += (pCur->aiLen[i] = (u32)(v/6));
}
+ if( n>pCur->nData ) break;
}
- return SQLITE_OK;
+ if( i<pTab->nVal ){
+ pCur->zData = 0;
+ return 0;
+ }
+ return 1;
}
/*
@@ -424,88 +637,104 @@ static int lsm1Column(
int i /* Which column to return */
){
lsm1_cursor *pCur = (lsm1_cursor*)cur;
- switch( i ){
- case LSM1_COLUMN_BLOBKEY: {
- const void *pVal;
- int nVal;
- if( lsm_csr_key(pCur->pLsmCur, &pVal, &nVal)==LSM_OK ){
+ lsm1_vtab *pTab = (lsm1_vtab*)(cur->pVtab);
+ if( i==0 ){
+ /* The key column */
+ const void *pVal;
+ int nVal;
+ if( lsm_csr_key(pCur->pLsmCur, &pVal, &nVal)==LSM_OK ){
+ if( pTab->keyType==SQLITE_BLOB ){
sqlite3_result_blob(ctx, pVal, nVal, SQLITE_TRANSIENT);
+ }else if( pTab->keyType==SQLITE_TEXT ){
+ sqlite3_result_text(ctx,(const char*)pVal, nVal, SQLITE_TRANSIENT);
+ }else{
+ const unsigned char *z = (const unsigned char*)pVal;
+ sqlite3_uint64 v1;
+ lsm1GetVarint64(z, nVal, &v1);
+ sqlite3_result_int64(ctx, (sqlite3_int64)v1);
}
- break;
}
- case LSM1_COLUMN_KEY: {
- const unsigned char *pVal;
+ }else if( i>pTab->nVal ){
+ if( i==pTab->nVal+2 ){ /* lsm1_key */
+ const void *pVal;
int nVal;
- if( lsm_csr_key(pCur->pLsmCur, (const void**)&pVal, &nVal)==LSM_OK
- && nVal>=1
- ){
- if( pVal[0]==LSM1_TYPE_BLOB ){
- sqlite3_result_blob(ctx, (const void*)&pVal[1],nVal-1,
- SQLITE_TRANSIENT);
- }else if( pVal[0]==LSM1_TYPE_TEXT ){
- sqlite3_result_text(ctx, (const char*)&pVal[1],nVal-1,
- SQLITE_TRANSIENT);
- }else if( nVal>=2 && nVal<=10 &&
- (pVal[0]==LSM1_TYPE_POSITIVE || pVal[0]==LSM1_TYPE_NEGATIVE)
- ){
- sqlite3_int64 iVal;
- lsm1GetVarint64(pVal+1, nVal-1, (sqlite3_uint64*)&iVal);
- sqlite3_result_int64(ctx, iVal);
- }
+ if( lsm_csr_key(pCur->pLsmCur, &pVal, &nVal)==LSM_OK ){
+ sqlite3_result_blob(ctx, pVal, nVal, SQLITE_TRANSIENT);
}
- break;
- }
- case LSM1_COLUMN_BLOBVALUE: {
+ }else if( i==pTab->nVal+3 ){ /* lsm1_value */
const void *pVal;
int nVal;
- if( lsm_csr_value(pCur->pLsmCur, (const void**)&pVal, &nVal)==LSM_OK ){
+ if( lsm_csr_value(pCur->pLsmCur, &pVal, &nVal)==LSM_OK ){
sqlite3_result_blob(ctx, pVal, nVal, SQLITE_TRANSIENT);
}
- break;
}
- case LSM1_COLUMN_VALUE: {
- const unsigned char *aVal;
- int nVal;
- if( lsm_csr_value(pCur->pLsmCur, (const void**)&aVal, &nVal)==LSM_OK
- && nVal>=1
- ){
- switch( aVal[0] ){
- case SQLITE_FLOAT:
- case SQLITE_INTEGER: {
- sqlite3_uint64 x = 0;
- int j;
- for(j=1; j<nVal; j++){
- x = (x<<8) | aVal[j];
- }
- if( aVal[0]==SQLITE_INTEGER ){
- sqlite3_result_int64(ctx, *(sqlite3_int64*)&x);
- }else{
- double r;
- assert( sizeof(r)==sizeof(x) );
- memcpy(&r, &x, sizeof(r));
- sqlite3_result_double(ctx, r);
- }
- break;
- }
- case SQLITE_TEXT: {
- sqlite3_result_text(ctx, (char*)&aVal[1], nVal-1, SQLITE_TRANSIENT);
- break;
- }
- case SQLITE_BLOB: {
- sqlite3_result_blob(ctx, &aVal[1], nVal-1, SQLITE_TRANSIENT);
- break;
- }
+ }else if( lsm1DecodeValues(pCur) ){
+ /* The i-th value column (where leftmost is 1) */
+ const u8 *zData;
+ u32 nData;
+ i--;
+ zData = pCur->zData + pCur->aiOfst[i];
+ nData = pCur->aiLen[i];
+ switch( pCur->aeType[i] ){
+ case 0: { /* in-line integer */
+ sqlite3_result_int(ctx, pCur->aiOfst[i]);
+ break;
+ }
+ case SQLITE_INTEGER: {
+ sqlite3_int64 v;
+ lsm1GetSignedVarint64(zData, nData, &v);
+ sqlite3_result_int64(ctx, v);
+ break;
+ }
+ case SQLITE_FLOAT: {
+ double v;
+ if( nData==sizeof(v) ){
+ memcpy(&v, zData, sizeof(v));
+ sqlite3_result_double(ctx, v);
}
+ break;
+ }
+ case SQLITE_TEXT: {
+ sqlite3_result_text(ctx, (const char*)zData, nData, SQLITE_TRANSIENT);
+ break;
+ }
+ case SQLITE_BLOB: {
+ sqlite3_result_blob(ctx, zData, nData, SQLITE_TRANSIENT);
+ break;
+ }
+ default: {
+ /* A NULL. Do nothing */
}
- break;
- }
- default: {
- break;
}
}
return SQLITE_OK;
}
+/* Parameter "pValue" contains an SQL value that is to be used as
+** a key in an LSM table. The type of the key is determined by
+** "keyType". Extract the raw bytes used for the key in LSM1.
+*/
+static void lsm1KeyFromValue(
+ int keyType, /* The key type */
+ sqlite3_value *pValue, /* The key value */
+ u8 *pBuf, /* Storage space for a generated key */
+ const u8 **ppKey, /* OUT: the bytes of the key */
+ int *pnKey /* OUT: size of the key */
+){
+ if( keyType==SQLITE_BLOB ){
+ *ppKey = (const u8*)sqlite3_value_blob(pValue);
+ *pnKey = sqlite3_value_bytes(pValue);
+ }else if( keyType==SQLITE_TEXT ){
+ *ppKey = (const u8*)sqlite3_value_text(pValue);
+ *pnKey = sqlite3_value_bytes(pValue);
+ }else{
+ sqlite3_int64 v = sqlite3_value_int64(pValue);
+ if( v<0 ) v = 0;
+ *pnKey = lsm1PutVarint64(pBuf, v);
+ *ppKey = pBuf;
+ }
+}
+
/* Move to the first row to return.
*/
static int lsm1Filter(
@@ -514,21 +743,74 @@ static int lsm1Filter(
int argc, sqlite3_value **argv
){
lsm1_cursor *pCur = (lsm1_cursor *)pVtabCursor;
+ lsm1_vtab *pTab = (lsm1_vtab*)(pCur->base.pVtab);
int rc = LSM_OK;
+ int seekType = -1;
+ const u8 *pVal = 0;
+ int nVal;
+ u8 keyType = pTab->keyType;
+ u8 aKey1[16];
+
pCur->atEof = 1;
- if( idxNum==1 ){
- assert( argc==1 );
- pCur->isDesc = 0;
- pCur->bUnique = 1;
- if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
- const void *pVal = sqlite3_value_blob(argv[0]);
- int nVal = sqlite3_value_bytes(argv[0]);
- rc = lsm_csr_seek(pCur->pLsmCur, pVal, nVal, LSM_SEEK_EQ);
+ sqlite3_free(pCur->pKey2);
+ pCur->pKey2 = 0;
+ if( idxNum<99 ){
+ lsm1KeyFromValue(keyType, argv[0], aKey1, &pVal, &nVal);
+ }
+ switch( idxNum ){
+ case 0: { /* key==argv[0] */
+ assert( argc==1 );
+ seekType = LSM_SEEK_EQ;
+ pCur->isDesc = 0;
+ pCur->bUnique = 1;
+ break;
}
+ case 1: { /* key>=argv[0] AND key<=argv[1] */
+ u8 aKey[12];
+ seekType = LSM_SEEK_GE;
+ pCur->isDesc = 0;
+ pCur->bUnique = 0;
+ if( keyType==SQLITE_INTEGER ){
+ sqlite3_int64 v = sqlite3_value_int64(argv[1]);
+ if( v<0 ) v = 0;
+ pCur->nKey2 = lsm1PutVarint64(aKey, (sqlite3_uint64)v);
+ pCur->pKey2 = sqlite3_malloc( pCur->nKey2 );
+ if( pCur->pKey2==0 ) return SQLITE_NOMEM;
+ memcpy(pCur->pKey2, aKey, pCur->nKey2);
+ }else{
+ pCur->nKey2 = sqlite3_value_bytes(argv[1]);
+ pCur->pKey2 = sqlite3_malloc( pCur->nKey2 );
+ if( pCur->pKey2==0 ) return SQLITE_NOMEM;
+ if( keyType==SQLITE_BLOB ){
+ memcpy(pCur->pKey2, sqlite3_value_blob(argv[1]), pCur->nKey2);
+ }else{
+ memcpy(pCur->pKey2, sqlite3_value_text(argv[1]), pCur->nKey2);
+ }
+ }
+ break;
+ }
+ case 2: { /* key>=argv[0] */
+ seekType = LSM_SEEK_GE;
+ pCur->isDesc = 0;
+ pCur->bUnique = 0;
+ break;
+ }
+ case 3: { /* key<=argv[0] */
+ seekType = LSM_SEEK_LE;
+ pCur->isDesc = 1;
+ pCur->bUnique = 0;
+ break;
+ }
+ default: { /* full table scan */
+ pCur->isDesc = 0;
+ pCur->bUnique = 0;
+ break;
+ }
+ }
+ if( pVal ){
+ rc = lsm_csr_seek(pCur->pLsmCur, pVal, nVal, seekType);
}else{
rc = lsm_csr_first(pCur->pLsmCur);
- pCur->isDesc = 0;
- pCur->bUnique = 0;
}
if( rc==LSM_OK && lsm_csr_valid(pCur->pLsmCur)!=0 ){
pCur->atEof = 0;
@@ -540,59 +822,87 @@ static int lsm1Filter(
** Only comparisons against the key are allowed. The idxNum defines
** which comparisons are available:
**
-** 0 Full table scan only
-** bit 1 key==?1 single argument for ?1
-** bit 2 key>?1
-** bit 3 key>=?1
-** bit 4 key<?N (N==1 if bits 2,3 clear, or 2 if bits2,3 set)
-** bit 5 key<=?N (N==1 if bits 2,3 clear, or 2 if bits2,3 set)
-** bit 6 Use blobkey instead of key
-**
-** To put it another way:
-**
-** 0 Full table scan.
-** 1 key==?1
-** 2 key>?1
-** 4 key>=?1
-** 8 key<?1
-** 10 key>?1 AND key<?2
-** 12 key>=?1 AND key<?2
-** 16 key<=?1
-** 18 key>?1 AND key<=?2
-** 20 key>=?1 AND key<=?2
-** 33..52 Use blobkey in place of key...
+** 0 key==?1
+** 1 key>=?1 AND key<=?2
+** 2 key>?1 or key>=?1
+** 3 key<?1 or key<=?1
+** 99 Full table scan only
*/
static int lsm1BestIndex(
sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo
){
int i; /* Loop over constraints */
- int idxNum = 0; /* The query plan bitmask */
+ int idxNum = 99; /* The query plan */
int nArg = 0; /* Number of arguments to xFilter */
- int eqIdx = -1; /* Index of the key== constraint, or -1 if none */
+ int argIdx = -1; /* Index of the key== constraint, or -1 if none */
+ int iIdx2 = -1; /* The index of the second key */
+ int omit1 = 0;
+ int omit2 = 0;
const struct sqlite3_index_constraint *pConstraint;
pConstraint = pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint && idxNum<16; i++, pConstraint++){
if( pConstraint->usable==0 ) continue;
- if( pConstraint->iColumn!=LSM1_COLUMN_KEY ) continue;
- if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ if( pConstraint->iColumn!=0 ) continue;
switch( pConstraint->op ){
case SQLITE_INDEX_CONSTRAINT_EQ: {
- eqIdx = i;
- idxNum = 1;
+ if( idxNum>0 ){
+ argIdx = i;
+ iIdx2 = -1;
+ idxNum = 0;
+ omit1 = 1;
+ }
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_GE:
+ case SQLITE_INDEX_CONSTRAINT_GT: {
+ if( idxNum==99 ){
+ argIdx = i;
+ idxNum = 2;
+ omit1 = pConstraint->op==SQLITE_INDEX_CONSTRAINT_GE;
+ }else if( idxNum==3 ){
+ iIdx2 = idxNum;
+ omit2 = omit1;
+ argIdx = i;
+ idxNum = 1;
+ omit1 = pConstraint->op==SQLITE_INDEX_CONSTRAINT_GE;
+ }
+ break;
+ }
+ case SQLITE_INDEX_CONSTRAINT_LE:
+ case SQLITE_INDEX_CONSTRAINT_LT: {
+ if( idxNum==99 ){
+ argIdx = i;
+ idxNum = 3;
+ omit1 = pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE;
+ }else if( idxNum==2 ){
+ iIdx2 = i;
+ idxNum = 1;
+ omit1 = pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE;
+ }
break;
}
}
}
- if( eqIdx>=0 ){
- pIdxInfo->aConstraintUsage[eqIdx].argvIndex = ++nArg;
- pIdxInfo->aConstraintUsage[eqIdx].omit = 1;
+ if( argIdx>=0 ){
+ pIdxInfo->aConstraintUsage[argIdx].argvIndex = ++nArg;
+ pIdxInfo->aConstraintUsage[argIdx].omit = omit1;
}
- if( idxNum==1 ){
+ if( iIdx2>=0 ){
+ pIdxInfo->aConstraintUsage[iIdx2].argvIndex = ++nArg;
+ pIdxInfo->aConstraintUsage[iIdx2].omit = omit2;
+ }
+ if( idxNum==0 ){
pIdxInfo->estimatedCost = (double)1;
pIdxInfo->estimatedRows = 1;
pIdxInfo->orderByConsumed = 1;
+ }else if( idxNum==1 ){
+ pIdxInfo->estimatedCost = (double)100;
+ pIdxInfo->estimatedRows = 100;
+ }else if( idxNum<99 ){
+ pIdxInfo->estimatedCost = (double)5000;
+ pIdxInfo->estimatedRows = 5000;
}else{
/* Full table scan */
pIdxInfo->estimatedCost = (double)2147483647;
@@ -615,98 +925,84 @@ int lsm1Update(
sqlite_int64 *pRowid
){
lsm1_vtab *p = (lsm1_vtab*)pVTab;
- const void *pKey;
- void *pFree = 0;
- int nKey;
- int eType;
+ int nKey, nKey2;
+ int i;
int rc = LSM_OK;
- sqlite3_value *pValue;
- const unsigned char *pVal;
- unsigned char *pData;
- int nVal;
- unsigned char pSpace[100];
+ const u8 *pKey, *pKey2;
+ unsigned char aKey[16];
+ unsigned char pSpace[16];
+ lsm1_vblob val;
if( argc==1 ){
- pVTab->zErrMsg = sqlite3_mprintf("cannot DELETE");
- return SQLITE_ERROR;
+ /* DELETE the record whose key is argv[0] */
+ lsm1KeyFromValue(p->keyType, argv[0], aKey, &pKey, &nKey);
+ lsm_delete(p->pDb, pKey, nKey);
+ return SQLITE_OK;
}
+
if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){
- pVTab->zErrMsg = sqlite3_mprintf("cannot UPDATE");
- return SQLITE_ERROR;
+ /* An UPDATE */
+ lsm1KeyFromValue(p->keyType, argv[0], aKey, &pKey, &nKey);
+ lsm1KeyFromValue(p->keyType, argv[1], pSpace, &pKey2, &nKey2);
+ if( nKey!=nKey2 || memcmp(pKey, pKey2, nKey)!=0 ){
+ /* The UPDATE changes the PRIMARY KEY value. DELETE the old key */
+ lsm_delete(p->pDb, pKey, nKey);
+ }
+ /* Fall through into the INSERT case to complete the UPDATE */
}
- /* "INSERT INTO tab(command) VALUES('....')" is used to implement
+ /* "INSERT INTO tab(lsm1_command) VALUES('....')" is used to implement
** special commands.
*/
- if( sqlite3_value_type(argv[2+LSM1_COLUMN_COMMAND])!=SQLITE_NULL ){
+ if( sqlite3_value_type(argv[3+p->nVal])!=SQLITE_NULL ){
return SQLITE_OK;
}
- if( sqlite3_value_type(argv[2+LSM1_COLUMN_BLOBKEY])==SQLITE_BLOB ){
- /* Use the blob key exactly as supplied */
- pKey = sqlite3_value_blob(argv[2+LSM1_COLUMN_BLOBKEY]);
- nKey = sqlite3_value_bytes(argv[2+LSM1_COLUMN_BLOBKEY]);
- }else{
- /* Use a key encoding that sorts in lexicographical order */
- rc = lsm1EncodeKey(argv[2+LSM1_COLUMN_KEY],
- (unsigned char**)&pKey,&nKey,
- pSpace,sizeof(pSpace));
- if( rc ) return rc;
- if( pKey!=(const void*)pSpace ) pFree = (void*)pKey;
- }
- if( sqlite3_value_type(argv[2+LSM1_COLUMN_BLOBVALUE])==SQLITE_BLOB ){
- pVal = sqlite3_value_blob(argv[2+LSM1_COLUMN_BLOBVALUE]);
- nVal = sqlite3_value_bytes(argv[2+LSM1_COLUMN_BLOBVALUE]);
- rc = lsm_insert(p->pDb, pKey, nKey, pVal, nVal);
- }else{
- pValue = argv[2+LSM1_COLUMN_VALUE];
- eType = sqlite3_value_type(pValue);
+ lsm1KeyFromValue(p->keyType, argv[2], aKey, &pKey, &nKey);
+ memset(&val, 0, sizeof(val));
+ for(i=0; i<p->nVal; i++){
+ sqlite3_value *pArg = argv[3+i];
+ u8 eType = sqlite3_value_type(pArg);
switch( eType ){
case SQLITE_NULL: {
- rc = lsm_delete(p->pDb, pKey, nKey);
+ lsm1VblobAppendVarint(&val, SQLITE_NULL);
break;
}
- case SQLITE_BLOB:
- case SQLITE_TEXT: {
- if( eType==SQLITE_TEXT ){
- pVal = sqlite3_value_text(pValue);
- }else{
- pVal = (unsigned char*)sqlite3_value_blob(pValue);
- }
- nVal = sqlite3_value_bytes(pValue);
- pData = sqlite3_malloc( nVal+1 );
- if( pData==0 ){
- rc = SQLITE_NOMEM;
+ case SQLITE_INTEGER: {
+ sqlite3_int64 v = sqlite3_value_int64(pArg);
+ if( v>=0 && v<=240/6 ){
+ lsm1VblobAppendVarint(&val, v*6);
}else{
- pData[0] = (unsigned char)eType;
- memcpy(&pData[1], pVal, nVal);
- rc = lsm_insert(p->pDb, pKey, nKey, pData, nVal+1);
- sqlite3_free(pData);
+ int n = lsm1PutSignedVarint64(pSpace, v);
+ lsm1VblobAppendVarint(&val, SQLITE_INTEGER + n*6);
+ lsm1VblobAppend(&val, pSpace, n);
}
break;
}
- case SQLITE_INTEGER:
case SQLITE_FLOAT: {
- sqlite3_uint64 x;
- unsigned char aVal[9];
- int i;
- if( eType==SQLITE_INTEGER ){
- *(sqlite3_int64*)&x = sqlite3_value_int64(pValue);
- }else{
- double r = sqlite3_value_double(pValue);
- assert( sizeof(r)==sizeof(x) );
- memcpy(&x, &r, sizeof(r));
- }
- for(i=8; x>0 && i>=1; i--){
- aVal[i] = x & 0xff;
- x >>= 8;
- }
- aVal[i] = (unsigned char)eType;
- rc = lsm_insert(p->pDb, pKey, nKey, &aVal[i], 9-i);
+ double r = sqlite3_value_double(pArg);
+ lsm1VblobAppendVarint(&val, SQLITE_FLOAT + 8*6);
+ lsm1VblobAppend(&val, (u8*)&r, sizeof(r));
+ break;
+ }
+ case SQLITE_BLOB: {
+ int n = sqlite3_value_bytes(pArg);
+ lsm1VblobAppendVarint(&val, n*6 + SQLITE_BLOB);
+ lsm1VblobAppend(&val, sqlite3_value_blob(pArg), n);
+ break;
+ }
+ case SQLITE_TEXT: {
+ int n = sqlite3_value_bytes(pArg);
+ lsm1VblobAppendVarint(&val, n*6 + SQLITE_TEXT);
+ lsm1VblobAppend(&val, sqlite3_value_text(pArg), n);
break;
}
}
}
- sqlite3_free(pFree);
+ if( val.errNoMem ){
+ return SQLITE_NOMEM;
+ }
+ rc = lsm_insert(p->pDb, pKey, nKey, val.a, val.n);
+ sqlite3_free(val.a);
return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR;
}
diff --git a/third_party/sqlite/src/ext/lsm1/test/lsm1_simple.test b/third_party/sqlite/src/ext/lsm1/test/lsm1_simple.test
index cd071f9..8ebc641 100644
--- a/third_party/sqlite/src/ext/lsm1/test/lsm1_simple.test
+++ b/third_party/sqlite/src/ext/lsm1/test/lsm1_simple.test
@@ -19,38 +19,75 @@ load_lsm1_vtab db
forcedelete testlsm.db
-do_execsql_test 1.0 {
- CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db);
+do_execsql_test 100 {
+ CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db,a,UINT,b,c,d);
PRAGMA table_info(x1);
} {
- 0 key {} 0 {} 0
- 1 blobkey {} 0 {} 0
- 2 value {} 0 {} 0
- 3 blobvalue {} 0 {} 0
+ 0 a UINT 1 {} 1
+ 1 b {} 0 {} 0
+ 2 c {} 0 {} 0
+ 3 d {} 0 {} 0
}
-do_execsql_test 1.1 {
- INSERT INTO x1(blobkey, blobvalue) VALUES(x'abcd', x'1234');
- SELECT quote(blobkey), quote(blobvalue) FROM x1;
-} {X'ABCD' X'1234'}
+do_execsql_test 110 {
+ INSERT INTO x1(a,b,c,d) VALUES(15, 11, 22, 33),(8,'banjo',x'333231',NULL),
+ (12,NULL,3.25,-559281390);
+ SELECT a, quote(b), quote(c), quote(d) FROM x1;
+} {8 'banjo' X'333231' NULL 12 NULL 3.25 -559281390 15 11 22 33}
+do_execsql_test 111 {
+ SELECT a, quote(lsm1_key), quote(lsm1_value) FROM x1;
+} {8 X'08' X'2162616E6A6F1633323105' 12 X'0C' X'05320000000000000A401FFB42ABE9DB' 15 X'0F' X'4284C6'}
-do_catchsql_test 1.2 {
- UPDATE x1 SET blobvalue = x'7890' WHERE blobkey = x'abcd';
-} {1 {cannot UPDATE}}
+do_execsql_test 120 {
+ UPDATE x1 SET d = d+1.0 WHERE a=15;
+ SELECT a, quote(b), quote(c), quote(d) FROM x1;
+} {8 'banjo' X'333231' NULL 12 NULL 3.25 -559281390 15 11 22 34.0}
-do_catchsql_test 1.3 {
- DELETE FROM x1 WHERE blobkey = x'abcd'
-} {1 {cannot DELETE}}
+do_execsql_test 130 {
+ UPDATE x1 SET a=123456789 WHERE a=12;
+ SELECT a, quote(b), quote(c), quote(d) FROM x1;
+} {8 'banjo' X'333231' NULL 15 11 22 34.0 123456789 NULL 3.25 -559281390}
+do_execsql_test 131 {
+ SELECT quote(lsm1_key), printf('0x%x',a) FROM x1 WHERE a > 100000000;
+} {X'FB075BCD15' 0x75bcd15}
-do_test 1.4 {
+do_execsql_test 140 {
+ DELETE FROM x1 WHERE a=15;
+ SELECT a, quote(b), quote(c), quote(d) FROM x1;
+} {8 'banjo' X'333231' NULL 123456789 NULL 3.25 -559281390}
+
+do_test 150 {
lsort [glob testlsm.db*]
} {testlsm.db testlsm.db-log testlsm.db-shm}
db close
-do_test 1.5 {
+do_test 160 {
lsort [glob testlsm.db*]
} {testlsm.db}
-finish_test
+forcedelete testlsm.db
+forcedelete test.db
+sqlite3 db test.db
+load_lsm1_vtab db
+
+do_execsql_test 200 {
+ CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db,a,TEXT,b,c,d);
+ PRAGMA table_info(x1);
+} {
+ 0 a TEXT 1 {} 1
+ 1 b {} 0 {} 0
+ 2 c {} 0 {} 0
+ 3 d {} 0 {} 0
+}
+do_execsql_test 210 {
+ INSERT INTO x1(a,b,c,d) VALUES(15, 11, 22, 33),(8,'banjo',x'333231',NULL),
+ (12,NULL,3.25,-559281390);
+ SELECT quote(a), quote(b), quote(c), quote(d), '|' FROM x1;
+} {'12' NULL 3.25 -559281390 | '15' 11 22 33 | '8' 'banjo' X'333231' NULL |}
+do_execsql_test 211 {
+ SELECT quote(a), quote(lsm1_key), quote(lsm1_value), '|' FROM x1;
+} {'12' X'3132' X'05320000000000000A401FFB42ABE9DB' | '15' X'3135' X'4284C6' | '8' X'38' X'2162616E6A6F1633323105' |}
+
+finish_test
diff --git a/third_party/sqlite/src/ext/misc/csv.c b/third_party/sqlite/src/ext/misc/csv.c
index e66ba56..83d6cb3f 100644
--- a/third_party/sqlite/src/ext/misc/csv.c
+++ b/third_party/sqlite/src/ext/misc/csv.c
@@ -78,7 +78,7 @@ struct CsvReader {
int nAlloc; /* Space allocated for z[] */
int nLine; /* Current line number */
int bNotFirst; /* True if prior text has been seen */
- char cTerm; /* Character that terminated the most recent field */
+ int cTerm; /* Character that terminated the most recent field */
size_t iIn; /* Next unread character in the input buffer */
size_t nIn; /* Number of characters in the input buffer */
char *zIn; /* The input buffer */
@@ -166,7 +166,7 @@ static int csv_getc(CsvReader *p){
if( p->in!=0 ) return csv_getc_refill(p);
return EOF;
}
- return p->zIn[p->iIn++];
+ return ((unsigned char*)p->zIn)[p->iIn++];
}
/* Increase the size of p->z and append character c to the end.
@@ -680,16 +680,16 @@ static int csvtabNext(sqlite3_vtab_cursor *cur){
i++;
}
}while( pCur->rdr.cTerm==',' );
- while( i<pTab->nCol ){
- sqlite3_free(pCur->azVal[i]);
- pCur->azVal[i] = 0;
- pCur->aLen[i] = 0;
- i++;
- }
- if( z==0 || pCur->rdr.cTerm==EOF ){
+ if( z==0 || (pCur->rdr.cTerm==EOF && i<pTab->nCol) ){
pCur->iRowid = -1;
}else{
pCur->iRowid++;
+ while( i<pTab->nCol ){
+ sqlite3_free(pCur->azVal[i]);
+ pCur->azVal[i] = 0;
+ pCur->aLen[i] = 0;
+ i++;
+ }
}
return SQLITE_OK;
}
diff --git a/third_party/sqlite/src/ext/misc/mmapwarm.c b/third_party/sqlite/src/ext/misc/mmapwarm.c
new file mode 100644
index 0000000..f4d1a01
--- /dev/null
+++ b/third_party/sqlite/src/ext/misc/mmapwarm.c
@@ -0,0 +1,108 @@
+/*
+** 2017-09-18
+**
+** 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.
+**
+*************************************************************************
+**
+*/
+
+#include "sqlite3.h"
+
+
+/*
+** This function is used to touch each page of a mapping of a memory
+** mapped SQLite database. Assuming that the system has sufficient free
+** memory and supports sufficiently large mappings, this causes the OS
+** to cache the entire database in main memory, making subsequent
+** database accesses faster.
+**
+** If the second parameter to this function is not NULL, it is the name of
+** the specific database to operate on (i.e. "main" or the name of an
+** attached database).
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+** It is not considered an error if the file is not memory-mapped, or if
+** the mapping does not span the entire file. If an error does occur, a
+** transaction may be left open on the database file.
+**
+** It is illegal to call this function when the database handle has an
+** open transaction. SQLITE_MISUSE is returned in this case.
+*/
+int sqlite3_mmap_warm(sqlite3 *db, const char *zDb){
+ int rc = SQLITE_OK;
+ char *zSql = 0;
+ int pgsz = 0;
+ int nTotal = 0;
+
+ if( 0==sqlite3_get_autocommit(db) ) return SQLITE_MISUSE;
+
+ /* Open a read-only transaction on the file in question */
+ zSql = sqlite3_mprintf("BEGIN; SELECT * FROM %s%q%ssqlite_master",
+ (zDb ? "'" : ""), (zDb ? zDb : ""), (zDb ? "'." : "")
+ );
+ if( zSql==0 ) return SQLITE_NOMEM;
+ rc = sqlite3_exec(db, zSql, 0, 0, 0);
+ sqlite3_free(zSql);
+
+ /* Find the SQLite page size of the file */
+ if( rc==SQLITE_OK ){
+ zSql = sqlite3_mprintf("PRAGMA %s%q%spage_size",
+ (zDb ? "'" : ""), (zDb ? zDb : ""), (zDb ? "'." : "")
+ );
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ sqlite3_stmt *pPgsz = 0;
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pPgsz, 0);
+ sqlite3_free(zSql);
+ if( rc==SQLITE_OK ){
+ if( sqlite3_step(pPgsz)==SQLITE_ROW ){
+ pgsz = sqlite3_column_int(pPgsz, 0);
+ }
+ rc = sqlite3_finalize(pPgsz);
+ }
+ if( rc==SQLITE_OK && pgsz==0 ){
+ rc = SQLITE_ERROR;
+ }
+ }
+ }
+
+ /* Touch each mmap'd page of the file */
+ if( rc==SQLITE_OK ){
+ int rc2;
+ sqlite3_file *pFd = 0;
+ rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFd);
+ if( rc==SQLITE_OK && pFd->pMethods->iVersion>=3 ){
+ sqlite3_int64 iPg = 1;
+ sqlite3_io_methods const *p = pFd->pMethods;
+ while( 1 ){
+ unsigned char *pMap;
+ rc = p->xFetch(pFd, pgsz*iPg, pgsz, (void**)&pMap);
+ if( rc!=SQLITE_OK || pMap==0 ) break;
+
+ nTotal += pMap[0];
+ nTotal += pMap[pgsz-1];
+
+ rc = p->xUnfetch(pFd, pgsz*iPg, (void*)pMap);
+ if( rc!=SQLITE_OK ) break;
+ iPg++;
+ }
+ sqlite3_log(SQLITE_OK,
+ "sqlite3_mmap_warm_cache: Warmed up %d pages of %s", iPg==1?0:iPg,
+ sqlite3_db_filename(db, zDb)
+ );
+ }
+
+ rc2 = sqlite3_exec(db, "END", 0, 0, 0);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+
+ return rc;
+}
+
diff --git a/third_party/sqlite/src/ext/misc/series.c b/third_party/sqlite/src/ext/misc/series.c
index dc7dc0e..d02a690 100644
--- a/third_party/sqlite/src/ext/misc/series.c
+++ b/third_party/sqlite/src/ext/misc/series.c
@@ -195,8 +195,9 @@ static int seriesColumn(
}
/*
-** Return the rowid for the current row. In this implementation, the
-** rowid is the same as the output value.
+** Return the rowid for the current row. In this implementation, the
+** first row returned is assigned rowid value 1, and each subsequent
+** row a value 1 more than that of the previous.
*/
static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
series_cursor *pCur = (series_cursor*)cur;
diff --git a/third_party/sqlite/src/ext/misc/unionvtab.c b/third_party/sqlite/src/ext/misc/unionvtab.c
index 0ba783a..b382bc5 100644
--- a/third_party/sqlite/src/ext/misc/unionvtab.c
+++ b/third_party/sqlite/src/ext/misc/unionvtab.c
@@ -10,8 +10,8 @@
**
*************************************************************************
**
-** This file contains the implementation of the "unionvtab" virtual
-** table. This module provides read-only access to multiple tables,
+** This file contains the implementation of the "unionvtab" and "swarmvtab"
+** virtual tables. These modules provide read-only access to multiple tables,
** possibly in multiple database files, via a single database object.
** The source tables must have the following characteristics:
**
@@ -25,26 +25,48 @@
**
** * Each table must contain a distinct range of rowid values.
**
-** A "unionvtab" virtual table is created as follows:
+** The difference between the two virtual table modules is that for
+** "unionvtab", all source tables must be located in the main database or
+** in databases ATTACHed to the main database by the user. For "swarmvtab",
+** the tables may be located in any database file on disk. The "swarmvtab"
+** implementation takes care of opening and closing database files
+** automatically.
**
-** CREATE VIRTUAL TABLE <name> USING unionvtab(<sql statement>);
+** UNIONVTAB
**
-** The implementation evalutes <sql statement> whenever a unionvtab virtual
-** table is created or opened. It should return one row for each source
-** database table. The four columns required of each row are:
+** A "unionvtab" virtual table is created as follows:
**
-** 1. The name of the database containing the table ("main" or "temp" or
-** the name of an attached database). Or NULL to indicate that all
-** databases should be searched for the table in the usual fashion.
+** CREATE VIRTUAL TABLE <name> USING unionvtab(<sql-statement>);
**
-** 2. The name of the database table.
+** The implementation evalutes <sql statement> whenever a unionvtab virtual
+** table is created or opened. It should return one row for each source
+** database table. The four columns required of each row are:
**
-** 3. The smallest rowid in the range of rowids that may be stored in the
-** database table (an integer).
+** 1. The name of the database containing the table ("main" or "temp" or
+** the name of an attached database). Or NULL to indicate that all
+** databases should be searched for the table in the usual fashion.
**
-** 4. The largest rowid in the range of rowids that may be stored in the
-** database table (an integer).
+** 2. The name of the database table.
**
+** 3. The smallest rowid in the range of rowids that may be stored in the
+** database table (an integer).
+**
+** 4. The largest rowid in the range of rowids that may be stored in the
+** database table (an integer).
+**
+** SWARMVTAB
+**
+** A "swarmvtab" virtual table is created similarly to a unionvtab table:
+**
+** CREATE VIRTUAL TABLE <name>
+** USING swarmvtab(<sql-statement>, <callback>);
+**
+** The difference is that for a swarmvtab table, the first column returned
+** by the <sql statement> must return a path or URI that can be used to open
+** the database file containing the source table. The <callback> option
+** is optional. If included, it is the name of an application-defined
+** SQL function that is invoked with the URI of the file, if the file
+** does not already exist on disk.
*/
#include "sqlite3ext.h"
@@ -65,6 +87,30 @@ SQLITE_EXTENSION_INIT1
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
#endif
+/*
+** The following is also copied from sqliteInt.h. To facilitate coverage
+** testing.
+*/
+#ifndef ALWAYS
+# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
+# 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
+
+/*
+** The swarmvtab module attempts to keep the number of open database files
+** at or below this limit. This may not be possible if there are too many
+** simultaneous queries.
+*/
+#define SWARMVTAB_MAX_OPEN 9
+
typedef struct UnionCsr UnionCsr;
typedef struct UnionTab UnionTab;
typedef struct UnionSrc UnionSrc;
@@ -79,6 +125,12 @@ struct UnionSrc {
char *zTab; /* Source table name */
sqlite3_int64 iMin; /* Minimum rowid */
sqlite3_int64 iMax; /* Maximum rowid */
+
+ /* Fields used by swarmvtab only */
+ char *zFile; /* Database file containing table zTab */
+ int nUser; /* Current number of users */
+ sqlite3 *db; /* Database handle */
+ UnionSrc *pNextClosable; /* Next in list of closable sources */
};
/*
@@ -87,9 +139,17 @@ struct UnionSrc {
struct UnionTab {
sqlite3_vtab base; /* Base class - must be first */
sqlite3 *db; /* Database handle */
+ int bSwarm; /* 1 for "swarmvtab", 0 for "unionvtab" */
int iPK; /* INTEGER PRIMARY KEY column, or -1 */
int nSrc; /* Number of elements in the aSrc[] array */
UnionSrc *aSrc; /* Array of source tables, sorted by rowid */
+
+ /* Used by swarmvtab only */
+ char *zSourceStr; /* Expected unionSourceToStr() value */
+ char *zNotFoundCallback; /* UDF to invoke if file not found on open */
+ UnionSrc *pClosable; /* First in list of closable sources */
+ int nOpen; /* Current number of open sources */
+ int nMaxOpen; /* Maximum number of open sources */
};
/*
@@ -98,9 +158,21 @@ struct UnionTab {
struct UnionCsr {
sqlite3_vtab_cursor base; /* Base class - must be first */
sqlite3_stmt *pStmt; /* SQL statement to run */
+
+ /* Used by swarmvtab only */
+ sqlite3_int64 iMaxRowid; /* Last rowid to visit */
+ int iTab; /* Index of table read by pStmt */
};
/*
+** Given UnionTab table pTab and UnionSrc object pSrc, return the database
+** handle that should be used to access the table identified by pSrc. This
+** is the main db handle for "unionvtab" tables, or the source-specific
+** handle for "swarmvtab".
+*/
+#define unionGetDb(pTab, pSrc) ((pTab)->bSwarm ? (pSrc)->db : (pTab)->db)
+
+/*
** If *pRc is other than SQLITE_OK when this function is called, it
** always returns NULL. Otherwise, it attempts to allocate and return
** a pointer to nByte bytes of zeroed memory. If the memory allocation
@@ -160,7 +232,7 @@ static void unionDequote(char *z){
int iIn = 1;
int iOut = 0;
if( q=='[' ) q = ']';
- while( z[iIn] ){
+ while( ALWAYS(z[iIn]) ){
if( z[iIn]==q ){
if( z[iIn+1]!=q ){
/* Character iIn was the close quote. */
@@ -202,6 +274,7 @@ static sqlite3_stmt *unionPrepare(
char **pzErr /* OUT: Error message */
){
sqlite3_stmt *pRet = 0;
+ assert( pzErr );
if( *pRc==SQLITE_OK ){
int rc = sqlite3_prepare_v2(db, zSql, -1, &pRet, 0);
if( rc!=SQLITE_OK ){
@@ -250,6 +323,7 @@ static sqlite3_stmt *unionPreparePrintf(
** In this case, *pzErr may be set to point to an error message
** buffer allocated by sqlite3_malloc().
*/
+#if 0
static void unionReset(int *pRc, sqlite3_stmt *pStmt, char **pzErr){
int rc = sqlite3_reset(pStmt);
if( *pRc==SQLITE_OK ){
@@ -259,15 +333,39 @@ static void unionReset(int *pRc, sqlite3_stmt *pStmt, char **pzErr){
}
}
}
+#endif
/*
** Call sqlite3_finalize() on SQL statement pStmt. If *pRc is set to
** SQLITE_OK when this function is called, then it is set to the
** value returned by sqlite3_finalize() before this function exits.
*/
-static void unionFinalize(int *pRc, sqlite3_stmt *pStmt){
+static void unionFinalize(int *pRc, sqlite3_stmt *pStmt, char **pzErr){
+ sqlite3 *db = sqlite3_db_handle(pStmt);
int rc = sqlite3_finalize(pStmt);
- if( *pRc==SQLITE_OK ) *pRc = rc;
+ if( *pRc==SQLITE_OK ){
+ *pRc = rc;
+ if( rc ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }
+ }
+}
+
+/*
+** This function is a no-op for unionvtab. For swarmvtab, it attempts to
+** close open database files until at most nMax are open. An SQLite error
+** code is returned if an error occurs, or SQLITE_OK otherwise.
+*/
+static void unionCloseSources(UnionTab *pTab, int nMax){
+ while( pTab->pClosable && pTab->nOpen>nMax ){
+ UnionSrc **pp;
+ for(pp=&pTab->pClosable; (*pp)->pNextClosable; pp=&(*pp)->pNextClosable);
+ assert( (*pp)->db );
+ sqlite3_close((*pp)->db);
+ (*pp)->db = 0;
+ *pp = 0;
+ pTab->nOpen--;
+ }
}
/*
@@ -278,9 +376,14 @@ static int unionDisconnect(sqlite3_vtab *pVtab){
UnionTab *pTab = (UnionTab*)pVtab;
int i;
for(i=0; i<pTab->nSrc; i++){
- sqlite3_free(pTab->aSrc[i].zDb);
- sqlite3_free(pTab->aSrc[i].zTab);
+ UnionSrc *pSrc = &pTab->aSrc[i];
+ sqlite3_free(pSrc->zDb);
+ sqlite3_free(pSrc->zTab);
+ sqlite3_free(pSrc->zFile);
+ sqlite3_close(pSrc->db);
}
+ sqlite3_free(pTab->zSourceStr);
+ sqlite3_free(pTab->zNotFoundCallback);
sqlite3_free(pTab->aSrc);
sqlite3_free(pTab);
}
@@ -288,6 +391,38 @@ static int unionDisconnect(sqlite3_vtab *pVtab){
}
/*
+** Check that the table identified by pSrc is a rowid table. If not,
+** return SQLITE_ERROR and set (*pzErr) to point to an English language
+** error message. If the table is a rowid table and no error occurs,
+** return SQLITE_OK and leave (*pzErr) unmodified.
+*/
+static int unionIsIntkeyTable(
+ sqlite3 *db, /* Database handle */
+ UnionSrc *pSrc, /* Source table to test */
+ char **pzErr /* OUT: Error message */
+){
+ int bPk = 0;
+ const char *zType = 0;
+ int rc;
+
+ sqlite3_table_column_metadata(
+ db, pSrc->zDb, pSrc->zTab, "_rowid_", &zType, 0, 0, &bPk, 0
+ );
+ rc = sqlite3_errcode(db);
+ if( rc==SQLITE_ERROR
+ || (rc==SQLITE_OK && (!bPk || sqlite3_stricmp("integer", zType)))
+ ){
+ rc = SQLITE_ERROR;
+ *pzErr = sqlite3_mprintf("no such rowid table: %s%s%s",
+ (pSrc->zDb ? pSrc->zDb : ""),
+ (pSrc->zDb ? "." : ""),
+ pSrc->zTab
+ );
+ }
+ return rc;
+}
+
+/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. In this case it returns NULL.
**
@@ -306,41 +441,27 @@ static int unionDisconnect(sqlite3_vtab *pVtab){
*/
static char *unionSourceToStr(
int *pRc, /* IN/OUT: Error code */
- sqlite3 *db, /* Database handle */
+ UnionTab *pTab, /* Virtual table object */
UnionSrc *pSrc, /* Source table to test */
- sqlite3_stmt *pStmt,
char **pzErr /* OUT: Error message */
){
char *zRet = 0;
if( *pRc==SQLITE_OK ){
- int bPk = 0;
- const char *zType = 0;
- int rc;
-
- sqlite3_table_column_metadata(
- db, pSrc->zDb, pSrc->zTab, "_rowid_", &zType, 0, 0, &bPk, 0
+ sqlite3 *db = unionGetDb(pTab, pSrc);
+ int rc = unionIsIntkeyTable(db, pSrc, pzErr);
+ sqlite3_stmt *pStmt = unionPrepare(&rc, db,
+ "SELECT group_concat(quote(name) || '.' || quote(type)) "
+ "FROM pragma_table_info(?, ?)", pzErr
);
- rc = sqlite3_errcode(db);
- if( rc==SQLITE_ERROR
- || (rc==SQLITE_OK && (!bPk || sqlite3_stricmp("integer", zType)))
- ){
- rc = SQLITE_ERROR;
- *pzErr = sqlite3_mprintf("no such rowid table: %s%s%s",
- (pSrc->zDb ? pSrc->zDb : ""),
- (pSrc->zDb ? "." : ""),
- pSrc->zTab
- );
- }
-
if( rc==SQLITE_OK ){
sqlite3_bind_text(pStmt, 1, pSrc->zTab, -1, SQLITE_STATIC);
sqlite3_bind_text(pStmt, 2, pSrc->zDb, -1, SQLITE_STATIC);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
- zRet = unionStrdup(&rc, (const char*)sqlite3_column_text(pStmt, 0));
+ const char *z = (const char*)sqlite3_column_text(pStmt, 0);
+ zRet = unionStrdup(&rc, z);
}
- unionReset(&rc, pStmt, pzErr);
+ unionFinalize(&rc, pStmt, pzErr);
}
-
*pRc = rc;
}
@@ -356,34 +477,152 @@ static char *unionSourceToStr(
** other error occurs, SQLITE_OK is returned.
*/
static int unionSourceCheck(UnionTab *pTab, char **pzErr){
- const char *zSql =
- "SELECT group_concat(quote(name) || '.' || quote(type)) "
- "FROM pragma_table_info(?, ?)";
int rc = SQLITE_OK;
+ char *z0 = 0;
+ int i;
- if( pTab->nSrc==0 ){
- *pzErr = sqlite3_mprintf("no source tables configured");
- rc = SQLITE_ERROR;
- }else{
- sqlite3_stmt *pStmt = 0;
- char *z0 = 0;
- int i;
+ assert( *pzErr==0 );
+ z0 = unionSourceToStr(&rc, pTab, &pTab->aSrc[0], pzErr);
+ for(i=1; i<pTab->nSrc; i++){
+ char *z = unionSourceToStr(&rc, pTab, &pTab->aSrc[i], pzErr);
+ if( rc==SQLITE_OK && sqlite3_stricmp(z, z0) ){
+ *pzErr = sqlite3_mprintf("source table schema mismatch");
+ rc = SQLITE_ERROR;
+ }
+ sqlite3_free(z);
+ }
+ sqlite3_free(z0);
- pStmt = unionPrepare(&rc, pTab->db, zSql, pzErr);
- if( rc==SQLITE_OK ){
- z0 = unionSourceToStr(&rc, pTab->db, &pTab->aSrc[0], pStmt, pzErr);
+ return rc;
+}
+
+
+/*
+** Try to open the swarmvtab database. If initially unable, invoke the
+** not-found callback UDF and then try again.
+*/
+static int unionOpenDatabaseInner(UnionTab *pTab, UnionSrc *pSrc, char **pzErr){
+ int rc = SQLITE_OK;
+ static const int openFlags =
+ SQLITE_OPEN_READONLY | SQLITE_OPEN_URI;
+ rc = sqlite3_open_v2(pSrc->zFile, &pSrc->db, openFlags, 0);
+ if( rc==SQLITE_OK ) return rc;
+ if( pTab->zNotFoundCallback ){
+ char *zSql = sqlite3_mprintf("SELECT \"%w\"(%Q);",
+ pTab->zNotFoundCallback, pSrc->zFile);
+ sqlite3_close(pSrc->db);
+ pSrc->db = 0;
+ if( zSql==0 ){
+ *pzErr = sqlite3_mprintf("out of memory");
+ return SQLITE_NOMEM;
}
- for(i=1; i<pTab->nSrc; i++){
- char *z = unionSourceToStr(&rc, pTab->db, &pTab->aSrc[i], pStmt, pzErr);
- if( rc==SQLITE_OK && sqlite3_stricmp(z, z0) ){
- *pzErr = sqlite3_mprintf("source table schema mismatch");
- rc = SQLITE_ERROR;
+ rc = sqlite3_exec(pTab->db, zSql, 0, 0, pzErr);
+ sqlite3_free(zSql);
+ if( rc ) return rc;
+ rc = sqlite3_open_v2(pSrc->zFile, &pSrc->db, openFlags, 0);
+ }
+ if( rc!=SQLITE_OK ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(pSrc->db));
+ }
+ return rc;
+}
+
+/*
+** This function may only be called for swarmvtab tables. The results of
+** calling it on a unionvtab table are undefined.
+**
+** For a swarmvtab table, this function ensures that source database iSrc
+** is open. If the database is opened successfully and the schema is as
+** expected, or if it is already open when this function is called, SQLITE_OK
+** is returned.
+**
+** Alternatively If an error occurs while opening the databases, or if the
+** database schema is unsuitable, an SQLite error code is returned and (*pzErr)
+** may be set to point to an English language error message. In this case it is
+** the responsibility of the caller to eventually free the error message buffer
+** using sqlite3_free().
+*/
+static int unionOpenDatabase(UnionTab *pTab, int iSrc, char **pzErr){
+ int rc = SQLITE_OK;
+ UnionSrc *pSrc = &pTab->aSrc[iSrc];
+
+ assert( pTab->bSwarm && iSrc<pTab->nSrc );
+ if( pSrc->db==0 ){
+ unionCloseSources(pTab, pTab->nMaxOpen-1);
+ rc = unionOpenDatabaseInner(pTab, pSrc, pzErr);
+ if( rc==SQLITE_OK ){
+ char *z = unionSourceToStr(&rc, pTab, pSrc, pzErr);
+ if( rc==SQLITE_OK ){
+ if( pTab->zSourceStr==0 ){
+ pTab->zSourceStr = z;
+ }else{
+ if( sqlite3_stricmp(z, pTab->zSourceStr) ){
+ *pzErr = sqlite3_mprintf("source table schema mismatch");
+ rc = SQLITE_ERROR;
+ }
+ sqlite3_free(z);
+ }
}
- sqlite3_free(z);
}
- unionFinalize(&rc, pStmt);
- sqlite3_free(z0);
+ if( rc==SQLITE_OK ){
+ pSrc->pNextClosable = pTab->pClosable;
+ pTab->pClosable = pSrc;
+ pTab->nOpen++;
+ }else{
+ sqlite3_close(pSrc->db);
+ pSrc->db = 0;
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+** This function is a no-op for unionvtab tables. For swarmvtab, increment
+** the reference count for source table iTab. If the reference count was
+** zero before it was incremented, also remove the source from the closable
+** list.
+*/
+static void unionIncrRefcount(UnionTab *pTab, int iTab){
+ if( pTab->bSwarm ){
+ UnionSrc *pSrc = &pTab->aSrc[iTab];
+ assert( pSrc->nUser>=0 && pSrc->db );
+ if( pSrc->nUser==0 ){
+ UnionSrc **pp;
+ for(pp=&pTab->pClosable; *pp!=pSrc; pp=&(*pp)->pNextClosable);
+ *pp = pSrc->pNextClosable;
+ pSrc->pNextClosable = 0;
+ }
+ pSrc->nUser++;
+ }
+}
+
+/*
+** Finalize the SQL statement pCsr->pStmt and return the result.
+**
+** If this is a swarmvtab table (not unionvtab) and pCsr->pStmt was not
+** NULL when this function was called, also decrement the reference
+** count on the associated source table. If this means the source tables
+** refcount is now zero, add it to the closable list.
+*/
+static int unionFinalizeCsrStmt(UnionCsr *pCsr){
+ int rc = SQLITE_OK;
+ if( pCsr->pStmt ){
+ UnionTab *pTab = (UnionTab*)pCsr->base.pVtab;
+ UnionSrc *pSrc = &pTab->aSrc[pCsr->iTab];
+ rc = sqlite3_finalize(pCsr->pStmt);
+ pCsr->pStmt = 0;
+ if( pTab->bSwarm ){
+ pSrc->nUser--;
+ assert( pSrc->nUser>=0 );
+ if( pSrc->nUser==0 ){
+ pSrc->pNextClosable = pTab->pClosable;
+ pTab->pClosable = pSrc;
+ }
+ unionCloseSources(pTab, pTab->nMaxOpen);
+ }
}
return rc;
}
@@ -393,10 +632,11 @@ static int unionSourceCheck(UnionTab *pTab, char **pzErr){
**
** The argv[] array contains the following:
**
-** argv[0] -> module name ("unionvtab")
+** argv[0] -> module name ("unionvtab" or "swarmvtab")
** argv[1] -> database name
** argv[2] -> table name
** argv[3] -> SQL statement
+** argv[4] -> not-found callback UDF name
*/
static int unionConnect(
sqlite3 *db,
@@ -407,14 +647,15 @@ static int unionConnect(
){
UnionTab *pTab = 0;
int rc = SQLITE_OK;
+ int bSwarm = (pAux==0 ? 0 : 1);
+ const char *zVtab = (bSwarm ? "swarmvtab" : "unionvtab");
- (void)pAux; /* Suppress harmless 'unused parameter' warning */
if( sqlite3_stricmp("temp", argv[1]) ){
/* unionvtab tables may only be created in the temp schema */
- *pzErr = sqlite3_mprintf("unionvtab tables must be created in TEMP schema");
+ *pzErr = sqlite3_mprintf("%s tables must be created in TEMP schema", zVtab);
rc = SQLITE_ERROR;
- }else if( argc!=4 ){
- *pzErr = sqlite3_mprintf("wrong number of arguments for unionvtab");
+ }else if( argc!=4 && argc!=5 ){
+ *pzErr = sqlite3_mprintf("wrong number of arguments for %s", zVtab);
rc = SQLITE_ERROR;
}else{
int nAlloc = 0; /* Allocated size of pTab->aSrc[] */
@@ -464,30 +705,60 @@ static int unionConnect(
rc = SQLITE_ERROR;
}
- pSrc = &pTab->aSrc[pTab->nSrc++];
- pSrc->zDb = unionStrdup(&rc, zDb);
- pSrc->zTab = unionStrdup(&rc, zTab);
- pSrc->iMin = iMin;
- pSrc->iMax = iMax;
+ if( rc==SQLITE_OK ){
+ pSrc = &pTab->aSrc[pTab->nSrc++];
+ pSrc->zTab = unionStrdup(&rc, zTab);
+ pSrc->iMin = iMin;
+ pSrc->iMax = iMax;
+ if( bSwarm ){
+ pSrc->zFile = unionStrdup(&rc, zDb);
+ }else{
+ pSrc->zDb = unionStrdup(&rc, zDb);
+ }
+ }
}
- unionFinalize(&rc, pStmt);
+ unionFinalize(&rc, pStmt, pzErr);
pStmt = 0;
- /* Verify that all source tables exist and have compatible schemas. */
+ /* Capture the not-found callback UDF name */
+ if( rc==SQLITE_OK && argc>=5 ){
+ pTab->zNotFoundCallback = unionStrdup(&rc, argv[4]);
+ unionDequote(pTab->zNotFoundCallback);
+ }
+
+ /* It is an error if the SELECT statement returned zero rows. If only
+ ** because there is no way to determine the schema of the virtual
+ ** table in this case. */
+ if( rc==SQLITE_OK && pTab->nSrc==0 ){
+ *pzErr = sqlite3_mprintf("no source tables configured");
+ rc = SQLITE_ERROR;
+ }
+
+ /* For unionvtab, verify that all source tables exist and have
+ ** compatible schemas. For swarmvtab, attach the first database and
+ ** check that the first table is a rowid table only. */
if( rc==SQLITE_OK ){
pTab->db = db;
- rc = unionSourceCheck(pTab, pzErr);
+ pTab->bSwarm = bSwarm;
+ pTab->nMaxOpen = SWARMVTAB_MAX_OPEN;
+ if( bSwarm ){
+ rc = unionOpenDatabase(pTab, 0, pzErr);
+ }else{
+ rc = unionSourceCheck(pTab, pzErr);
+ }
}
/* Compose a CREATE TABLE statement and pass it to declare_vtab() */
if( rc==SQLITE_OK ){
- pStmt = unionPreparePrintf(&rc, pzErr, db, "SELECT "
+ UnionSrc *pSrc = &pTab->aSrc[0];
+ sqlite3 *tdb = unionGetDb(pTab, pSrc);
+ pStmt = unionPreparePrintf(&rc, pzErr, tdb, "SELECT "
"'CREATE TABLE xyz('"
" || group_concat(quote(name) || ' ' || type, ', ')"
" || ')',"
"max((cid+1) * (type='INTEGER' COLLATE nocase AND pk=1))-1 "
"FROM pragma_table_info(%Q, ?)",
- pTab->aSrc[0].zTab, pTab->aSrc[0].zDb
+ pSrc->zTab, pSrc->zDb
);
}
if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
@@ -496,7 +767,7 @@ static int unionConnect(
pTab->iPK = sqlite3_column_int(pStmt, 1);
}
- unionFinalize(&rc, pStmt);
+ unionFinalize(&rc, pStmt, pzErr);
}
if( rc!=SQLITE_OK ){
@@ -508,7 +779,6 @@ static int unionConnect(
return rc;
}
-
/*
** xOpen
*/
@@ -526,25 +796,56 @@ static int unionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
*/
static int unionClose(sqlite3_vtab_cursor *cur){
UnionCsr *pCsr = (UnionCsr*)cur;
- sqlite3_finalize(pCsr->pStmt);
+ unionFinalizeCsrStmt(pCsr);
sqlite3_free(pCsr);
return SQLITE_OK;
}
+/*
+** This function does the work of the xNext() method. Except that, if it
+** returns SQLITE_ROW, it should be called again within the same xNext()
+** method call. See unionNext() for details.
+*/
+static int doUnionNext(UnionCsr *pCsr){
+ int rc = SQLITE_OK;
+ assert( pCsr->pStmt );
+ if( sqlite3_step(pCsr->pStmt)!=SQLITE_ROW ){
+ UnionTab *pTab = (UnionTab*)pCsr->base.pVtab;
+ rc = unionFinalizeCsrStmt(pCsr);
+ if( rc==SQLITE_OK && pTab->bSwarm ){
+ pCsr->iTab++;
+ if( pCsr->iTab<pTab->nSrc ){
+ UnionSrc *pSrc = &pTab->aSrc[pCsr->iTab];
+ if( pCsr->iMaxRowid>=pSrc->iMin ){
+ /* It is necessary to scan the next table. */
+ rc = unionOpenDatabase(pTab, pCsr->iTab, &pTab->base.zErrMsg);
+ pCsr->pStmt = unionPreparePrintf(&rc, &pTab->base.zErrMsg, pSrc->db,
+ "SELECT rowid, * FROM %Q %s %lld",
+ pSrc->zTab,
+ (pSrc->iMax>pCsr->iMaxRowid ? "WHERE _rowid_ <=" : "-- "),
+ pCsr->iMaxRowid
+ );
+ if( rc==SQLITE_OK ){
+ assert( pCsr->pStmt );
+ unionIncrRefcount(pTab, pCsr->iTab);
+ rc = SQLITE_ROW;
+ }
+ }
+ }
+ }
+ }
+
+ return rc;
+}
/*
** xNext
*/
static int unionNext(sqlite3_vtab_cursor *cur){
- UnionCsr *pCsr = (UnionCsr*)cur;
int rc;
- assert( pCsr->pStmt );
- if( sqlite3_step(pCsr->pStmt)!=SQLITE_ROW ){
- rc = sqlite3_finalize(pCsr->pStmt);
- pCsr->pStmt = 0;
- }else{
- rc = SQLITE_OK;
- }
+ do {
+ rc = doUnionNext((UnionCsr*)cur);
+ }while( rc==SQLITE_ROW );
return rc;
}
@@ -637,8 +938,7 @@ static int unionFilter(
}
}
- sqlite3_finalize(pCsr->pStmt);
- pCsr->pStmt = 0;
+ unionFinalizeCsrStmt(pCsr);
if( bZero ){
return SQLITE_OK;
}
@@ -674,12 +974,25 @@ static int unionFilter(
zSql = sqlite3_mprintf("%z %s rowid<=%lld", zSql, zWhere, iMax);
}
}
- }
+ if( pTab->bSwarm ){
+ pCsr->iTab = i;
+ pCsr->iMaxRowid = iMax;
+ rc = unionOpenDatabase(pTab, i, &pTab->base.zErrMsg);
+ break;
+ }
+ }
- if( zSql==0 ) return rc;
- pCsr->pStmt = unionPrepare(&rc, pTab->db, zSql, &pTab->base.zErrMsg);
- sqlite3_free(zSql);
+ if( zSql==0 ){
+ return rc;
+ }else{
+ sqlite3 *db = unionGetDb(pTab, &pTab->aSrc[pCsr->iTab]);
+ pCsr->pStmt = unionPrepare(&rc, db, zSql, &pTab->base.zErrMsg);
+ if( pCsr->pStmt ){
+ unionIncrRefcount(pTab, pCsr->iTab);
+ }
+ sqlite3_free(zSql);
+ }
if( rc!=SQLITE_OK ) return rc;
return unionNext(pVtabCursor);
}
@@ -791,8 +1104,13 @@ static int createUnionVtab(sqlite3 *db){
0, /* xRelease */
0 /* xRollbackTo */
};
+ int rc;
- return sqlite3_create_module(db, "unionvtab", &unionModule, 0);
+ rc = sqlite3_create_module(db, "unionvtab", &unionModule, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module(db, "swarmvtab", &unionModule, (void*)db);
+ }
+ return rc;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
diff --git a/third_party/sqlite/src/ext/misc/vtablog.c b/third_party/sqlite/src/ext/misc/vtablog.c
new file mode 100644
index 0000000..e183906
--- /dev/null
+++ b/third_party/sqlite/src/ext/misc/vtablog.c
@@ -0,0 +1,509 @@
+/*
+** 2017-08-10
+**
+** 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 a virtual table that prints diagnostic information
+** on stdout when its key interfaces are called. This is intended for
+** interactive analysis and debugging of virtual table interfaces.
+**
+** Usage example:
+**
+** .load ./vtablog
+** CREATE VIRTUAL TABLE temp.log USING vtablog(
+** schema='CREATE TABLE x(a,b,c)',
+** rows=25
+** );
+** SELECT * FROM log;
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+
+/* vtablog_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a vtablog virtual table
+*/
+typedef struct vtablog_vtab vtablog_vtab;
+struct vtablog_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ int nRow; /* Number of rows in the table */
+ int iInst; /* Instance number for this vtablog table */
+ int nCursor; /* Number of cursors created */
+};
+
+/* vtablog_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct vtablog_cursor vtablog_cursor;
+struct vtablog_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ int iCursor; /* Cursor number */
+ sqlite3_int64 iRowid; /* The rowid */
+};
+
+/* Skip leading whitespace. Return a pointer to the first non-whitespace
+** character, or to the zero terminator if the string has only whitespace */
+static const char *vtablog_skip_whitespace(const char *z){
+ while( isspace((unsigned char)z[0]) ) z++;
+ return z;
+}
+
+/* Remove trailing whitespace from the end of string z[] */
+static void vtablog_trim_whitespace(char *z){
+ size_t n = strlen(z);
+ while( n>0 && isspace((unsigned char)z[n]) ) n--;
+ z[n] = 0;
+}
+
+/* Dequote the string */
+static void vtablog_dequote(char *z){
+ int j;
+ char cQuote = z[0];
+ size_t i, n;
+
+ if( cQuote!='\'' && cQuote!='"' ) return;
+ n = strlen(z);
+ if( n<2 || z[n-1]!=z[0] ) return;
+ for(i=1, j=0; i<n-1; i++){
+ if( z[i]==cQuote && z[i+1]==cQuote ) i++;
+ z[j++] = z[i];
+ }
+ z[j] = 0;
+}
+
+/* Check to see if the string is of the form: "TAG = VALUE" with optional
+** whitespace before and around tokens. If it is, return a pointer to the
+** first character of VALUE. If it is not, return NULL.
+*/
+static const char *vtablog_parameter(const char *zTag, int nTag, const char *z){
+ z = vtablog_skip_whitespace(z);
+ if( strncmp(zTag, z, nTag)!=0 ) return 0;
+ z = vtablog_skip_whitespace(z+nTag);
+ if( z[0]!='=' ) return 0;
+ return vtablog_skip_whitespace(z+1);
+}
+
+/* Decode a parameter that requires a dequoted string.
+**
+** Return non-zero on an error.
+*/
+static int vtablog_string_parameter(
+ char **pzErr, /* Leave the error message here, if there is one */
+ const char *zParam, /* Parameter we are checking for */
+ const char *zArg, /* Raw text of the virtual table argment */
+ char **pzVal /* Write the dequoted string value here */
+){
+ const char *zValue;
+ zValue = vtablog_parameter(zParam,(int)strlen(zParam),zArg);
+ if( zValue==0 ) return 0;
+ if( *pzVal ){
+ *pzErr = sqlite3_mprintf("more than one '%s' parameter", zParam);
+ return 1;
+ }
+ *pzVal = sqlite3_mprintf("%s", zValue);
+ if( *pzVal==0 ){
+ *pzErr = sqlite3_mprintf("out of memory");
+ return 1;
+ }
+ vtablog_trim_whitespace(*pzVal);
+ vtablog_dequote(*pzVal);
+ return 0;
+}
+
+#if 0 /* not used - yet */
+/* Return 0 if the argument is false and 1 if it is true. Return -1 if
+** we cannot really tell.
+*/
+static int vtablog_boolean(const char *z){
+ if( sqlite3_stricmp("yes",z)==0
+ || sqlite3_stricmp("on",z)==0
+ || sqlite3_stricmp("true",z)==0
+ || (z[0]=='1' && z[1]==0)
+ ){
+ return 1;
+ }
+ if( sqlite3_stricmp("no",z)==0
+ || sqlite3_stricmp("off",z)==0
+ || sqlite3_stricmp("false",z)==0
+ || (z[0]=='0' && z[1]==0)
+ ){
+ return 0;
+ }
+ return -1;
+}
+#endif
+
+/*
+** The vtablogConnect() method is invoked to create a new
+** vtablog_vtab that describes the vtablog virtual table.
+**
+** Think of this routine as the constructor for vtablog_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the vtablog_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against vtablog will look like.
+*/
+static int vtablogConnectCreate(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr,
+ int isCreate
+){
+ static int nInst = 0;
+ vtablog_vtab *pNew;
+ int i;
+ int rc;
+ int iInst = ++nInst;
+ char *zSchema = 0;
+ char *zNRow = 0;
+
+ printf("vtablog%s(tab=%d):\n", isCreate ? "Create" : "Connect", iInst);
+ printf(" argc=%d\n", argc);
+ for(i=0; i<argc; i++){
+ printf(" argv[%d] = ", i);
+ if( argv[i] ){
+ printf("[%s]\n", argv[i]);
+ }else{
+ printf("NULL\n");
+ }
+ }
+
+ for(i=3; i<argc; i++){
+ const char *z = argv[i];
+ if( vtablog_string_parameter(pzErr, "schema", z, &zSchema) ){
+ return SQLITE_ERROR;
+ }
+ if( vtablog_string_parameter(pzErr, "rows", z, &zNRow) ){
+ return SQLITE_ERROR;
+ }
+ }
+
+ if( zSchema==0 ){
+ *pzErr = sqlite3_mprintf("no schema defined");
+ return SQLITE_ERROR;
+ }
+ rc = sqlite3_declare_vtab(db, zSchema);
+ 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->nRow = 10;
+ if( zNRow ) pNew->nRow = atoi(zNRow);
+ pNew->iInst = iInst;
+ }
+ return rc;
+}
+static int vtablogCreate(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ return vtablogConnectCreate(db,pAux,argc,argv,ppVtab,pzErr,1);
+}
+static int vtablogConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ return vtablogConnectCreate(db,pAux,argc,argv,ppVtab,pzErr,0);
+}
+
+
+/*
+** This method is the destructor for vtablog_cursor objects.
+*/
+static int vtablogDisconnect(sqlite3_vtab *pVtab){
+ vtablog_vtab *pTab = (vtablog_vtab*)pVtab;
+ printf("vtablogDisconnect(%d)\n", pTab->iInst);
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** This method is the destructor for vtablog_cursor objects.
+*/
+static int vtablogDestroy(sqlite3_vtab *pVtab){
+ vtablog_vtab *pTab = (vtablog_vtab*)pVtab;
+ printf("vtablogDestroy(%d)\n", pTab->iInst);
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new vtablog_cursor object.
+*/
+static int vtablogOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ vtablog_vtab *pTab = (vtablog_vtab*)p;
+ vtablog_cursor *pCur;
+ printf("vtablogOpen(tab=%d, cursor=%d)\n", pTab->iInst, ++pTab->nCursor);
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->iCursor = pTab->nCursor;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a vtablog_cursor.
+*/
+static int vtablogClose(sqlite3_vtab_cursor *cur){
+ vtablog_cursor *pCur = (vtablog_cursor*)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ printf("vtablogClose(tab=%d, cursor=%d)\n", pTab->iInst, pCur->iCursor);
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a vtablog_cursor to its next row of output.
+*/
+static int vtablogNext(sqlite3_vtab_cursor *cur){
+ vtablog_cursor *pCur = (vtablog_cursor*)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ printf("vtablogNext(tab=%d, cursor=%d) rowid %d -> %d\n",
+ pTab->iInst, pCur->iCursor, (int)pCur->iRowid, (int)pCur->iRowid+1);
+ pCur->iRowid++;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the vtablog_cursor
+** is currently pointing.
+*/
+static int vtablogColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ vtablog_cursor *pCur = (vtablog_cursor*)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ char zVal[50];
+
+ if( i<26 ){
+ sqlite3_snprintf(sizeof(zVal),zVal,"%c%d",
+ "abcdefghijklmnopqrstuvwyz"[i], pCur->iRowid);
+ }else{
+ sqlite3_snprintf(sizeof(zVal),zVal,"{%d}%d", i, pCur->iRowid);
+ }
+ printf("vtablogColumn(tab=%d, cursor=%d, i=%d): [%s]\n",
+ pTab->iInst, pCur->iCursor, i, zVal);
+ sqlite3_result_text(ctx, zVal, -1, SQLITE_TRANSIENT);
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int vtablogRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ vtablog_cursor *pCur = (vtablog_cursor*)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ printf("vtablogRowid(tab=%d, cursor=%d): %d\n",
+ pTab->iInst, pCur->iCursor, (int)pCur->iRowid);
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int vtablogEof(sqlite3_vtab_cursor *cur){
+ vtablog_cursor *pCur = (vtablog_cursor*)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ int rc = pCur->iRowid >= pTab->nRow;
+ printf("vtablogEof(tab=%d, cursor=%d): %d\n",
+ pTab->iInst, pCur->iCursor, rc);
+ return rc;
+}
+
+/*
+** Output an sqlite3_value object's value as an SQL literal.
+*/
+static void vtablogQuote(sqlite3_value *p){
+ char z[50];
+ switch( sqlite3_value_type(p) ){
+ case SQLITE_NULL: {
+ printf("NULL");
+ break;
+ }
+ case SQLITE_INTEGER: {
+ sqlite3_snprintf(50,z,"%lld", sqlite3_value_int64(p));
+ printf("%s", z);
+ break;
+ }
+ case SQLITE_FLOAT: {
+ sqlite3_snprintf(50,z,"%!.20g", sqlite3_value_double(p));
+ printf("%s", z);
+ break;
+ }
+ case SQLITE_BLOB: {
+ int n = sqlite3_value_bytes(p);
+ const unsigned char *z = (const unsigned char*)sqlite3_value_blob(p);
+ int i;
+ printf("x'");
+ for(i=0; i<n; i++) printf("%02x", z[i]);
+ printf("'");
+ break;
+ }
+ case SQLITE_TEXT: {
+ const char *z = (const char*)sqlite3_value_text(p);
+ int i;
+ char c;
+ for(i=0; (c = z[i])!=0 && c!='\''; i++){}
+ if( c==0 ){
+ printf("'%s'",z);
+ }else{
+ printf("'");
+ while( *z ){
+ for(i=0; (c = z[i])!=0 && c!='\''; i++){}
+ if( c=='\'' ) i++;
+ if( i ){
+ printf("%.*s", i, z);
+ z += i;
+ }
+ if( c=='\'' ){
+ printf("'");
+ continue;
+ }
+ if( c==0 ){
+ break;
+ }
+ z++;
+ }
+ printf("'");
+ }
+ break;
+ }
+ }
+}
+
+
+/*
+** This method is called to "rewind" the vtablog_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to vtablogColumn() or vtablogRowid() or
+** vtablogEof().
+*/
+static int vtablogFilter(
+ sqlite3_vtab_cursor *cur,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ vtablog_cursor *pCur = (vtablog_cursor *)cur;
+ vtablog_vtab *pTab = (vtablog_vtab*)cur->pVtab;
+ printf("vtablogFilter(tab=%d, cursor=%d):\n", pTab->iInst, pCur->iCursor);
+ pCur->iRowid = 0;
+ return SQLITE_OK;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the vtablog virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int vtablogBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ vtablog_vtab *pTab = (vtablog_vtab*)tab;
+ printf("vtablogBestIndex(tab=%d):\n", pTab->iInst);
+ pIdxInfo->estimatedCost = (double)500;
+ pIdxInfo->estimatedRows = 500;
+ return SQLITE_OK;
+}
+
+/*
+** SQLite invokes this method to INSERT, UPDATE, or DELETE content from
+** the table.
+**
+** This implementation does not actually make any changes to the table
+** content. It merely logs the fact that the method was invoked
+*/
+static int vtablogUpdate(
+ sqlite3_vtab *tab,
+ int argc,
+ sqlite3_value **argv,
+ sqlite_int64 *pRowid
+){
+ vtablog_vtab *pTab = (vtablog_vtab*)tab;
+ int i;
+ printf("vtablogUpdate(tab=%d):\n", pTab->iInst);
+ printf(" argc=%d\n", argc);
+ for(i=0; i<argc; i++){
+ printf(" argv[%d]=", i);
+ vtablogQuote(argv[i]);
+ printf("\n");
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** vtablog virtual table.
+*/
+static sqlite3_module vtablogModule = {
+ 0, /* iVersion */
+ vtablogCreate, /* xCreate */
+ vtablogConnect, /* xConnect */
+ vtablogBestIndex, /* xBestIndex */
+ vtablogDisconnect, /* xDisconnect */
+ vtablogDestroy, /* xDestroy */
+ vtablogOpen, /* xOpen - open a cursor */
+ vtablogClose, /* xClose - close a cursor */
+ vtablogFilter, /* xFilter - configure scan constraints */
+ vtablogNext, /* xNext - advance a cursor */
+ vtablogEof, /* xEof - check for end of scan */
+ vtablogColumn, /* xColumn - read data */
+ vtablogRowid, /* xRowid - read data */
+ vtablogUpdate, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+};
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_vtablog_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc;
+ SQLITE_EXTENSION_INIT2(pApi);
+ rc = sqlite3_create_module(db, "vtablog", &vtablogModule, 0);
+ return rc;
+}
diff --git a/third_party/sqlite/src/ext/rbu/rbu10.test b/third_party/sqlite/src/ext/rbu/rbu10.test
index 852fe27..98d6076 100644
--- a/third_party/sqlite/src/ext/rbu/rbu10.test
+++ b/third_party/sqlite/src/ext/rbu/rbu10.test
@@ -114,7 +114,7 @@ ifcapable fts3 {
INSERT INTO data_xt VALUES('a', 'b', 1, 0);
}
} msg] $msg
- } {1 {SQLITE_ERROR - SQL logic error or missing database}}
+ } {1 {SQLITE_ERROR - SQL logic error}}
}
#--------------------------------------------------------------------
diff --git a/third_party/sqlite/src/ext/rbu/rbufault.test b/third_party/sqlite/src/ext/rbu/rbufault.test
index c00f501..c7fb057 100644
--- a/third_party/sqlite/src/ext/rbu/rbufault.test
+++ b/third_party/sqlite/src/ext/rbu/rbufault.test
@@ -125,7 +125,7 @@ foreach {tn2 setup sql expect} {
{1 SQLITE_IOERR_WRITE}
{1 SQLITE_IOERR_READ}
{1 SQLITE_IOERR_FSYNC}
- {1 {SQLITE_ERROR - SQL logic error or missing database}}
+ {1 {SQLITE_ERROR - SQL logic error}}
{1 {SQLITE_ERROR - unable to open database: rbu.db}}
{1 {SQLITE_IOERR - unable to open database: rbu.db}}
}
diff --git a/third_party/sqlite/src/ext/rbu/rbufault3.test b/third_party/sqlite/src/ext/rbu/rbufault3.test
index 58e0451..3e8f8cc 100644
--- a/third_party/sqlite/src/ext/rbu/rbufault3.test
+++ b/third_party/sqlite/src/ext/rbu/rbufault3.test
@@ -31,7 +31,7 @@ foreach {fault errlist} {
{1 SQLITE_IOERR_READ}
{1 {SQLITE_IOERR - unable to open database: test.db2}}
{1 {SQLITE_ERROR - unable to open database: test.db2}}
- {1 {SQLITE_ERROR - SQL logic error or missing database}}
+ {1 {SQLITE_ERROR - SQL logic error}}
}
cantopen* {
diff --git a/third_party/sqlite/src/ext/rbu/rbufts.test b/third_party/sqlite/src/ext/rbu/rbufts.test
index d067de1..dd41482 100644
--- a/third_party/sqlite/src/ext/rbu/rbufts.test
+++ b/third_party/sqlite/src/ext/rbu/rbufts.test
@@ -119,14 +119,14 @@ do_test 3.2 {
CREATE TABLE data_ft(x, rbu_rowid, rbu_control);
INSERT INTO data_ft VALUES(NULL, 2, 1);
} } msg] $msg]
-} {1 {SQLITE_ERROR - SQL logic error or missing database]}}
+} {1 {SQLITE_ERROR - SQL logic error]}}
do_test 3.3 {
list [catch { apply_rbu_update test.db {
CREATE TABLE data_ft(x, rbu_rowid, rbu_control);
INSERT INTO data_ft VALUES('7 8 9', 1, 'x');
} } msg] $msg]
-} {1 {SQLITE_ERROR - SQL logic error or missing database]}}
+} {1 {SQLITE_ERROR - SQL logic error]}}
diff --git a/third_party/sqlite/src/ext/rbu/rbutemplimit.test b/third_party/sqlite/src/ext/rbu/rbutemplimit.test
new file mode 100644
index 0000000..066c61e
--- /dev/null
+++ b/third_party/sqlite/src/ext/rbu/rbutemplimit.test
@@ -0,0 +1,129 @@
+# 2014 August 30
+#
+# 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.
+#
+#***********************************************************************
+#
+
+source [file join [file dirname [info script]] rbu_common.tcl]
+set ::testprefix rbutemplimit
+
+db close
+sqlite3_shutdown
+sqlite3_config_uri 1
+
+proc setup_databases {} {
+ forcedelete test.db2
+ forcedelete test.db
+ sqlite3 db test.db
+ execsql {
+ -- Create target database schema.
+ --
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB(100), c BLOB(100));
+ CREATE TABLE t2(a INTEGER PRIMARY KEY, b BLOB(100), c BLOB(100));
+ CREATE INDEX i1b ON t1(b);
+ CREATE INDEX i1c ON t1(c);
+ CREATE INDEX i2b ON t2(b);
+ CREATE INDEX i2c ON t2(c);
+
+ -- Create a large RBU database.
+ --
+ ATTACH 'test.db2' AS rbu;
+ CREATE TABLE rbu.data_t1(a, b, c, rbu_control);
+ WITH s(i) AS (
+ VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<10000
+ )
+ INSERT INTO data_t1 SELECT i, randomblob(100), randomblob(100), 0 FROM s;
+ CREATE TABLE rbu.data_t2(a, b, c, rbu_control);
+ WITH s(i) AS (
+ VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<15000
+ )
+ INSERT INTO data_t2 SELECT i, randomblob(100), randomblob(100), 0 FROM s;
+ }
+ db close
+}
+
+proc run_rbu_cachesize {target rbu cachesize temp_limit} {
+ sqlite3rbu rbu $target $rbu
+ rbu temp_size_limit $temp_limit
+ sqlite3_exec_nr [rbu db 1] "PRAGMA cache_size = $cachesize"
+ while 1 {
+ set rc [rbu step]
+ set ::A([rbu temp_size]) 1
+ if {$rc!="SQLITE_OK"} break
+ }
+ list [catch {rbu close} msg] $msg
+}
+
+proc step_rbu_cachesize {target rbu stepsize cachesize temp_limit} {
+ set res ""
+ while 1 {
+ sqlite3rbu rbu $target $rbu
+ rbu temp_size_limit $temp_limit
+ sqlite3_exec_nr [rbu db 1] "PRAGMA cache_size = $cachesize"
+ for {set i 0} {$i < $stepsize} {incr i} {
+ set rc [rbu step]
+ set ::A([rbu temp_size]) 1
+ if {$rc!="SQLITE_OK"} break
+ }
+ set res [list [catch {rbu close} msg] $msg]
+ if {$res != "0 SQLITE_OK"} break
+ }
+ set res
+}
+
+do_test 1.1.0 { setup_databases } {}
+
+do_test 1.1.1 {
+ unset -nocomplain ::A
+ run_rbu_cachesize test.db test.db2 10 0
+} {0 SQLITE_DONE}
+
+do_test 1.1.2 { llength [array names ::A] } 3
+
+do_test 1.1.3 {
+ foreach {a0 a1 a2} [lsort -integer [array names ::A]] {}
+ list [expr $a0==0] \
+ [expr $a1>1048576] [expr $a1<1200000] \
+ [expr $a2>1500000] [expr $a2<1700000]
+} {1 1 1 1 1}
+
+do_test 1.2.1 {
+ setup_databases
+ run_rbu_cachesize test.db test.db2 10 1000000
+} {1 SQLITE_FULL}
+do_test 1.2.2 { info commands rbu } {}
+
+do_test 1.3.1 {
+ setup_databases
+ run_rbu_cachesize test.db test.db2 10 1300000
+} {1 SQLITE_FULL}
+do_test 1.3.2 { info commands rbu } {}
+
+do_test 1.4.1 {
+ setup_databases
+ run_rbu_cachesize test.db test.db2 10 1800000
+} {0 SQLITE_DONE}
+do_test 1.4.2 { info commands rbu } {}
+
+do_test 1.5.1 {
+ setup_databases
+ unset -nocomplain ::A
+ step_rbu_cachesize test.db test.db2 1000 10 2400000
+} {0 SQLITE_DONE}
+do_test 1.5.2 { info commands rbu } {}
+
+do_test 1.6.1 {
+ setup_databases
+ unset -nocomplain ::A
+ step_rbu_cachesize test.db test.db2 1000 10 1400000
+} {1 SQLITE_FULL}
+do_test 1.6.2 { info commands rbu } {}
+
+finish_test
+
diff --git a/third_party/sqlite/src/ext/rbu/sqlite3rbu.c b/third_party/sqlite/src/ext/rbu/sqlite3rbu.c
index ccba0f1..361d335 100644
--- a/third_party/sqlite/src/ext/rbu/sqlite3rbu.c
+++ b/third_party/sqlite/src/ext/rbu/sqlite3rbu.c
@@ -96,6 +96,13 @@
/* Maximum number of prepared UPDATE statements held by this module */
#define SQLITE_RBU_UPDATE_CACHESIZE 16
+/* Delta checksums disabled by default. Compile with -DRBU_ENABLE_DELTA_CKSUM
+** to enable checksum verification.
+*/
+#ifndef RBU_ENABLE_DELTA_CKSUM
+# define RBU_ENABLE_DELTA_CKSUM 0
+#endif
+
/*
** Swap two objects of type TYPE.
*/
@@ -371,6 +378,8 @@ struct sqlite3rbu {
int pgsz;
u8 *aBuf;
i64 iWalCksum;
+ i64 szTemp; /* Current size of all temp files in use */
+ i64 szTempLimit; /* Total size limit for temp files */
/* Used in RBU vacuum mode only */
int nRbu; /* Number of RBU VFS in the stack */
@@ -379,23 +388,33 @@ struct sqlite3rbu {
/*
** An rbu VFS is implemented using an instance of this structure.
+**
+** Variable pRbu is only non-NULL for automatically created RBU VFS objects.
+** It is NULL for RBU VFS objects created explicitly using
+** sqlite3rbu_create_vfs(). It is used to track the total amount of temp
+** space used by the RBU handle.
*/
struct rbu_vfs {
sqlite3_vfs base; /* rbu VFS shim methods */
sqlite3_vfs *pRealVfs; /* Underlying VFS */
sqlite3_mutex *mutex; /* Mutex to protect pMain */
+ sqlite3rbu *pRbu; /* Owner RBU object */
rbu_file *pMain; /* Linked list of main db files */
};
/*
** Each file opened by an rbu VFS is represented by an instance of
** the following structure.
+**
+** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable
+** "sz" is set to the current size of the database file.
*/
struct rbu_file {
sqlite3_file base; /* sqlite3_file methods */
sqlite3_file *pReal; /* Underlying file handle */
rbu_vfs *pRbuVfs; /* Pointer to the rbu_vfs object */
sqlite3rbu *pRbu; /* Pointer to rbu object (rbu target only) */
+ i64 sz; /* Size of file in bytes (temp only) */
int openFlags; /* Flags this file was opened with */
u32 iCookie; /* Cookie value for main db files */
@@ -458,6 +477,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
return v;
}
+#if RBU_ENABLE_DELTA_CKSUM
/*
** Compute a 32-bit checksum on the N-byte buffer. Return the result.
*/
@@ -492,6 +512,7 @@ static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){
}
return sum3;
}
+#endif
/*
** Apply a delta.
@@ -522,7 +543,7 @@ static int rbuDeltaApply(
){
unsigned int limit;
unsigned int total = 0;
-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
+#if RBU_ENABLE_DELTA_CKSUM
char *zOrigOut = zOut;
#endif
@@ -577,7 +598,7 @@ static int rbuDeltaApply(
case ';': {
zDelta++; lenDelta--;
zOut[0] = 0;
-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
+#if RBU_ENABLE_DELTA_CKSUM
if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){
/* ERROR: bad checksum */
return -1;
@@ -3409,6 +3430,7 @@ static void rbuCreateVfs(sqlite3rbu *p){
sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
assert( pVfs );
p->zVfsName = pVfs->zName;
+ ((rbu_vfs*)pVfs)->pRbu = p;
}
}
@@ -3781,6 +3803,7 @@ int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
/* Close the open database handle and VFS object. */
sqlite3_close(p->dbRbu);
sqlite3_close(p->dbMain);
+ assert( p->szTemp==0 );
rbuDeleteVfs(p);
sqlite3_free(p->aBuf);
sqlite3_free(p->aFrame);
@@ -3968,6 +3991,7 @@ int sqlite3rbu_savestate(sqlite3rbu *p){
*/
static void rbuUnlockShm(rbu_file *p){
+ assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
if( p->pRbu ){
int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock;
int i;
@@ -3981,6 +4005,18 @@ static void rbuUnlockShm(rbu_file *p){
}
/*
+*/
+static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){
+ sqlite3rbu *pRbu = pFd->pRbu;
+ i64 nDiff = nNew - pFd->sz;
+ pRbu->szTemp += nDiff;
+ pFd->sz = nNew;
+ assert( pRbu->szTemp>=0 );
+ if( pRbu->szTempLimit && pRbu->szTemp>pRbu->szTempLimit ) return SQLITE_FULL;
+ return SQLITE_OK;
+}
+
+/*
** Close an rbu file.
*/
static int rbuVfsClose(sqlite3_file *pFile){
@@ -4005,6 +4041,9 @@ static int rbuVfsClose(sqlite3_file *pFile){
rbuUnlockShm(p);
p->pReal->pMethods->xShmUnmap(p->pReal, 0);
}
+ else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
+ rbuUpdateTempSize(p, 0);
+ }
/* Close the underlying file handle */
rc = p->pReal->pMethods->xClose(p->pReal);
@@ -4122,11 +4161,19 @@ static int rbuVfsWrite(
assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
rc = rbuCaptureDbWrite(p->pRbu, iOfst);
}else{
- if( pRbu && pRbu->eStage==RBU_STAGE_OAL
- && (p->openFlags & SQLITE_OPEN_WAL)
- && iOfst>=pRbu->iOalSz
- ){
- pRbu->iOalSz = iAmt + iOfst;
+ if( pRbu ){
+ if( pRbu->eStage==RBU_STAGE_OAL
+ && (p->openFlags & SQLITE_OPEN_WAL)
+ && iOfst>=pRbu->iOalSz
+ ){
+ pRbu->iOalSz = iAmt + iOfst;
+ }else if( p->openFlags & SQLITE_OPEN_DELETEONCLOSE ){
+ i64 szNew = iAmt+iOfst;
+ if( szNew>p->sz ){
+ rc = rbuUpdateTempSize(p, szNew);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+ }
}
rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
@@ -4145,6 +4192,10 @@ static int rbuVfsWrite(
*/
static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
rbu_file *p = (rbu_file*)pFile;
+ if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
+ int rc = rbuUpdateTempSize(p, size);
+ if( rc!=SQLITE_OK ) return rc;
+ }
return p->pReal->pMethods->xTruncate(p->pReal, size);
}
@@ -4534,6 +4585,8 @@ static int rbuVfsOpen(
pDb->pWalFd = pFd;
}
}
+ }else{
+ pFd->pRbu = pRbuVfs->pRbu;
}
if( oflags & SQLITE_OPEN_MAIN_DB
@@ -4610,7 +4663,9 @@ static int rbuVfsAccess(
if( *pResOut ){
rc = SQLITE_CANTOPEN;
}else{
- *pResOut = 1;
+ sqlite3_int64 sz = 0;
+ rc = rbuVfsFileSize(&pDb->base, &sz);
+ *pResOut = (sz>0);
}
}
}
@@ -4799,6 +4854,20 @@ int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
return rc;
}
+/*
+** Configure the aggregate temp file size limit for this RBU handle.
+*/
+sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu *pRbu, sqlite3_int64 n){
+ if( n>=0 ){
+ pRbu->szTempLimit = n;
+ }
+ return pRbu->szTempLimit;
+}
+
+sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){
+ return pRbu->szTemp;
+}
+
/**************************************************************************/
diff --git a/third_party/sqlite/src/ext/rbu/sqlite3rbu.h b/third_party/sqlite/src/ext/rbu/sqlite3rbu.h
index 29c1028..07b8685 100644
--- a/third_party/sqlite/src/ext/rbu/sqlite3rbu.h
+++ b/third_party/sqlite/src/ext/rbu/sqlite3rbu.h
@@ -308,7 +308,7 @@ typedef struct sqlite3rbu sqlite3rbu;
** not work out of the box with zipvfs. Refer to the comment describing
** the zipvfs_create_vfs() API below for details on using RBU with zipvfs.
*/
-sqlite3rbu *sqlite3rbu_open(
+SQLITE_API sqlite3rbu *sqlite3rbu_open(
const char *zTarget,
const char *zRbu,
const char *zState
@@ -347,12 +347,34 @@ sqlite3rbu *sqlite3rbu_open(
** a description of the complications associated with using RBU with
** zipvfs databases.
*/
-sqlite3rbu *sqlite3rbu_vacuum(
+SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
const char *zTarget,
const char *zState
);
/*
+** Configure a limit for the amount of temp space that may be used by
+** the RBU handle passed as the first argument. The new limit is specified
+** in bytes by the second parameter. If it is positive, the limit is updated.
+** If the second parameter to this function is passed zero, then the limit
+** 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
+** indicates unlimited).
+**
+** If the temp space limit is exceeded during operation, an SQLITE_FULL
+** error is returned.
+*/
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64);
+
+/*
+** 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
** connection to access the target and rbu update databases. This
** API allows the application direct access to these database handles.
@@ -383,7 +405,7 @@ sqlite3rbu *sqlite3rbu_vacuum(
** Database handles returned by this function remain valid until the next
** call to any sqlite3rbu_xxx() function other than sqlite3rbu_db().
*/
-sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
+SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
/*
** Do some work towards applying the RBU update to the target db.
@@ -397,7 +419,7 @@ sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops
** that immediately return the same value.
*/
-int sqlite3rbu_step(sqlite3rbu *pRbu);
+SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
/*
** Force RBU to save its state to disk.
@@ -409,7 +431,7 @@ int sqlite3rbu_step(sqlite3rbu *pRbu);
**
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
*/
-int sqlite3rbu_savestate(sqlite3rbu *pRbu);
+SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
/*
** Close an RBU handle.
@@ -429,14 +451,14 @@ int sqlite3rbu_savestate(sqlite3rbu *pRbu);
** update has been partially applied, or SQLITE_DONE if it has been
** completely applied.
*/
-int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
+SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
/*
** 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.
*/
-sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
+SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
/*
** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100)
@@ -478,7 +500,7 @@ sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
** table exists but is not correctly populated, the value of the *pnOne
** output variable during stage 1 is undefined.
*/
-void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo);
+SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
/*
** Obtain an indication as to the current stage of an RBU update or vacuum.
@@ -516,7 +538,7 @@ void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo);
#define SQLITE_RBU_STATE_DONE 4
#define SQLITE_RBU_STATE_ERROR 5
-int sqlite3rbu_state(sqlite3rbu *pRbu);
+SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
/*
** Create an RBU VFS named zName that accesses the underlying file-system
@@ -560,7 +582,7 @@ int sqlite3rbu_state(sqlite3rbu *pRbu);
** file-system via "rbu" all the time, even if it only uses RBU functionality
** occasionally.
*/
-int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
+SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
/*
** Deregister and destroy an RBU vfs created by an earlier call to
@@ -570,7 +592,7 @@ int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
** before all database handles that use it have been closed, the results
** are undefined.
*/
-void sqlite3rbu_destroy_vfs(const char *zName);
+SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
#ifdef __cplusplus
} /* end of the 'extern "C"' block */
diff --git a/third_party/sqlite/src/ext/rbu/test_rbu.c b/third_party/sqlite/src/ext/rbu/test_rbu.c
index 9c61535..0973fba8 100644
--- a/third_party/sqlite/src/ext/rbu/test_rbu.c
+++ b/third_party/sqlite/src/ext/rbu/test_rbu.c
@@ -69,16 +69,18 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
int nArg;
const char *zUsage;
} aCmd[] = {
- {"step", 2, ""}, /* 0 */
- {"close", 2, ""}, /* 1 */
- {"create_rbu_delta", 2, ""}, /* 2 */
- {"savestate", 2, ""}, /* 3 */
- {"dbMain_eval", 3, "SQL"}, /* 4 */
- {"bp_progress", 2, ""}, /* 5 */
- {"db", 3, "RBU"}, /* 6 */
- {"state", 2, ""}, /* 7 */
- {"progress", 2, ""}, /* 8 */
- {"close_no_error", 2, ""}, /* 9 */
+ {"step", 2, ""}, /* 0 */
+ {"close", 2, ""}, /* 1 */
+ {"create_rbu_delta", 2, ""}, /* 2 */
+ {"savestate", 2, ""}, /* 3 */
+ {"dbMain_eval", 3, "SQL"}, /* 4 */
+ {"bp_progress", 2, ""}, /* 5 */
+ {"db", 3, "RBU"}, /* 6 */
+ {"state", 2, ""}, /* 7 */
+ {"progress", 2, ""}, /* 8 */
+ {"close_no_error", 2, ""}, /* 9 */
+ {"temp_size_limit", 3, "LIMIT"}, /* 10 */
+ {"temp_size", 2, ""}, /* 11 */
{0,0,0}
};
int iCmd;
@@ -194,6 +196,22 @@ static int SQLITE_TCLAPI test_sqlite3rbu_cmd(
break;
}
+ case 10: /* temp_size_limit */ {
+ sqlite3_int64 nLimit;
+ if( Tcl_GetWideIntFromObj(interp, objv[2], &nLimit) ){
+ ret = TCL_ERROR;
+ }else{
+ nLimit = sqlite3rbu_temp_size_limit(pRbu, nLimit);
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nLimit));
+ }
+ break;
+ }
+ case 11: /* temp_size */ {
+ sqlite3_int64 sz = sqlite3rbu_temp_size(pRbu);
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sz));
+ break;
+ }
+
default: /* seems unlikely */
assert( !"cannot happen" );
break;
diff --git a/third_party/sqlite/src/ext/repair/README.md b/third_party/sqlite/src/ext/repair/README.md
new file mode 100644
index 0000000..6430581
--- /dev/null
+++ b/third_party/sqlite/src/ext/repair/README.md
@@ -0,0 +1,16 @@
+This folder contains extensions and utility programs intended to analyze
+live database files, detect problems, and possibly fix them.
+
+As SQLite is being used on larger and larger databases, database sizes
+are growing into the terabyte range. At that size, hardware malfunctions
+and/or cosmic rays will occasionally corrupt a database file. Detecting
+problems and fixing errors a terabyte-sized databases can take hours or days,
+and it is undesirable to take applications that depend on the databases
+off-line for such a long time.
+The utilities in the folder are intended to provide mechanisms for
+detecting and fixing problems in large databases while those databases
+are in active use.
+
+The utilities and extensions in this folder are experimental and under
+active development at the time of this writing (2017-10-12). If and when
+they stabilize, this README will be updated to reflect that fact.
diff --git a/third_party/sqlite/src/ext/repair/checkfreelist.c b/third_party/sqlite/src/ext/repair/checkfreelist.c
new file mode 100644
index 0000000..16865e6
--- /dev/null
+++ b/third_party/sqlite/src/ext/repair/checkfreelist.c
@@ -0,0 +1,299 @@
+/*
+** 2017 October 11
+**
+** 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 module exports a single C function:
+**
+** int sqlite3_check_freelist(sqlite3 *db, const char *zDb);
+**
+** This function checks the free-list in database zDb (one of "main",
+** "temp", etc.) and reports any errors by invoking the sqlite3_log()
+** function. It returns SQLITE_OK if successful, or an SQLite error
+** code otherwise. It is not an error if the free-list is corrupted but
+** no IO or OOM errors occur.
+**
+** If this file is compiled and loaded as an SQLite loadable extension,
+** it adds an SQL function "checkfreelist" to the database handle, to
+** be invoked as follows:
+**
+** SELECT checkfreelist(<database-name>);
+**
+** This function performs the same checks as sqlite3_check_freelist(),
+** except that it returns all error messages as a single text value,
+** separated by newline characters. If the freelist is not corrupted
+** in any way, an empty string is returned.
+**
+** To compile this module for use as an SQLite loadable extension:
+**
+** gcc -Os -fPIC -shared checkfreelist.c -o checkfreelist.so
+*/
+
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+
+#ifndef SQLITE_AMALGAMATION
+# include <string.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <assert.h>
+# define ALWAYS(X) 1
+# define NEVER(X) 0
+ typedef unsigned char u8;
+ typedef unsigned short u16;
+ typedef unsigned int u32;
+#define get4byte(x) ( \
+ ((u32)((x)[0])<<24) + \
+ ((u32)((x)[1])<<16) + \
+ ((u32)((x)[2])<<8) + \
+ ((u32)((x)[3])) \
+)
+#endif
+
+/*
+** Execute a single PRAGMA statement and return the integer value returned
+** via output parameter (*pnOut).
+**
+** The SQL statement passed as the third argument should be a printf-style
+** format string containing a single "%s" which will be replace by the
+** value passed as the second argument. e.g.
+**
+** sqlGetInteger(db, "main", "PRAGMA %s.page_count", pnOut)
+**
+** executes "PRAGMA main.page_count" and stores the results in (*pnOut).
+*/
+static int sqlGetInteger(
+ sqlite3 *db, /* Database handle */
+ const char *zDb, /* Database name ("main", "temp" etc.) */
+ const char *zFmt, /* SQL statement format */
+ u32 *pnOut /* OUT: Integer value */
+){
+ int rc, rc2;
+ char *zSql;
+ sqlite3_stmt *pStmt = 0;
+ int bOk = 0;
+
+ zSql = sqlite3_mprintf(zFmt, zDb);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ }
+
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ *pnOut = (u32)sqlite3_column_int(pStmt, 0);
+ bOk = 1;
+ }
+
+ rc2 = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+ if( rc==SQLITE_OK && bOk==0 ) rc = SQLITE_ERROR;
+ return rc;
+}
+
+/*
+** Argument zFmt must be a printf-style format string and must be
+** followed by its required arguments. If argument pzOut is NULL,
+** then the results of printf()ing the format string are passed to
+** sqlite3_log(). Otherwise, they are appended to the string
+** at (*pzOut).
+*/
+static int checkFreelistError(char **pzOut, const char *zFmt, ...){
+ int rc = SQLITE_OK;
+ char *zErr = 0;
+ va_list ap;
+
+ va_start(ap, zFmt);
+ zErr = sqlite3_vmprintf(zFmt, ap);
+ if( zErr==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ if( pzOut ){
+ *pzOut = sqlite3_mprintf("%s%z%s", *pzOut?"\n":"", *pzOut, zErr);
+ if( *pzOut==0 ) rc = SQLITE_NOMEM;
+ }else{
+ sqlite3_log(SQLITE_ERROR, "checkfreelist: %s", zErr);
+ }
+ sqlite3_free(zErr);
+ }
+ va_end(ap);
+ return rc;
+}
+
+static int checkFreelist(
+ sqlite3 *db,
+ const char *zDb,
+ char **pzOut
+){
+ /* This query returns one row for each page on the free list. Each row has
+ ** two columns - the page number and page content. */
+ const char *zTrunk =
+ "WITH freelist_trunk(i, d, n) AS ("
+ "SELECT 1, NULL, sqlite_readint32(data, 32) "
+ "FROM sqlite_dbpage(:1) WHERE pgno=1 "
+ "UNION ALL "
+ "SELECT n, data, sqlite_readint32(data) "
+ "FROM freelist_trunk, sqlite_dbpage(:1) WHERE pgno=n "
+ ")"
+ "SELECT i, d FROM freelist_trunk WHERE i!=1;";
+
+ int rc, rc2; /* Return code */
+ sqlite3_stmt *pTrunk = 0; /* Compilation of zTrunk */
+ u32 nPage = 0; /* Number of pages in db */
+ u32 nExpected = 0; /* Expected number of free pages */
+ u32 nFree = 0; /* Number of pages on free list */
+
+ if( zDb==0 ) zDb = "main";
+
+ if( (rc = sqlGetInteger(db, zDb, "PRAGMA %s.page_count", &nPage))
+ || (rc = sqlGetInteger(db, zDb, "PRAGMA %s.freelist_count", &nExpected))
+ ){
+ return rc;
+ }
+
+ rc = sqlite3_prepare_v2(db, zTrunk, -1, &pTrunk, 0);
+ if( rc!=SQLITE_OK ) return rc;
+ sqlite3_bind_text(pTrunk, 1, zDb, -1, SQLITE_STATIC);
+ while( rc==SQLITE_OK && sqlite3_step(pTrunk)==SQLITE_ROW ){
+ u32 i;
+ u32 iTrunk = (u32)sqlite3_column_int(pTrunk, 0);
+ const u8 *aData = (const u8*)sqlite3_column_blob(pTrunk, 1);
+ int nData = sqlite3_column_bytes(pTrunk, 1);
+ u32 iNext = get4byte(&aData[0]);
+ u32 nLeaf = get4byte(&aData[4]);
+
+ if( nLeaf>((nData/4)-2-6) ){
+ rc = checkFreelistError(pzOut,
+ "leaf count out of range (%d) on trunk page %d",
+ (int)nLeaf, (int)iTrunk
+ );
+ nLeaf = (nData/4) - 2 - 6;
+ }
+
+ nFree += 1+nLeaf;
+ if( iNext>nPage ){
+ rc = checkFreelistError(pzOut,
+ "trunk page %d is out of range", (int)iNext
+ );
+ }
+
+ for(i=0; rc==SQLITE_OK && i<nLeaf; i++){
+ u32 iLeaf = get4byte(&aData[8 + 4*i]);
+ if( iLeaf==0 || iLeaf>nPage ){
+ rc = checkFreelistError(pzOut,
+ "leaf page %d is out of range (child %d of trunk page %d)",
+ (int)iLeaf, (int)i, (int)iTrunk
+ );
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK && nFree!=nExpected ){
+ rc = checkFreelistError(pzOut,
+ "free-list count mismatch: actual=%d header=%d",
+ (int)nFree, (int)nExpected
+ );
+ }
+
+ rc2 = sqlite3_finalize(pTrunk);
+ if( rc==SQLITE_OK ) rc = rc2;
+ return rc;
+}
+
+int sqlite3_check_freelist(sqlite3 *db, const char *zDb){
+ return checkFreelist(db, zDb, 0);
+}
+
+static void checkfreelist_function(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ const char *zDb;
+ int rc;
+ char *zOut = 0;
+ sqlite3 *db = sqlite3_context_db_handle(pCtx);
+
+ assert( nArg==1 );
+ zDb = (const char*)sqlite3_value_text(apArg[0]);
+ rc = checkFreelist(db, zDb, &zOut);
+ if( rc==SQLITE_OK ){
+ sqlite3_result_text(pCtx, zOut?zOut:"ok", -1, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_result_error_code(pCtx, rc);
+ }
+
+ sqlite3_free(zOut);
+}
+
+/*
+** An SQL function invoked as follows:
+**
+** sqlite_readint32(BLOB) -- Decode 32-bit integer from start of blob
+*/
+static void readint_function(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ const u8 *zBlob;
+ int nBlob;
+ int iOff = 0;
+ u32 iRet = 0;
+
+ if( nArg!=1 && nArg!=2 ){
+ sqlite3_result_error(
+ pCtx, "wrong number of arguments to function sqlite_readint32()", -1
+ );
+ return;
+ }
+ if( nArg==2 ){
+ iOff = sqlite3_value_int(apArg[1]);
+ }
+
+ zBlob = sqlite3_value_blob(apArg[0]);
+ nBlob = sqlite3_value_bytes(apArg[0]);
+
+ if( nBlob>=(iOff+4) ){
+ iRet = get4byte(&zBlob[iOff]);
+ }
+
+ sqlite3_result_int64(pCtx, (sqlite3_int64)iRet);
+}
+
+/*
+** Register the SQL functions.
+*/
+static int cflRegister(sqlite3 *db){
+ int rc = sqlite3_create_function(
+ db, "sqlite_readint32", -1, SQLITE_UTF8, 0, readint_function, 0, 0
+ );
+ if( rc!=SQLITE_OK ) return rc;
+ rc = sqlite3_create_function(
+ db, "checkfreelist", 1, SQLITE_UTF8, 0, checkfreelist_function, 0, 0
+ );
+ return rc;
+}
+
+/*
+** Extension load function.
+*/
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_checkfreelist_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ return cflRegister(db);
+}
diff --git a/third_party/sqlite/src/ext/rtree/rtree.c b/third_party/sqlite/src/ext/rtree/rtree.c
index 4ea6575..0a8adae 100644
--- a/third_party/sqlite/src/ext/rtree/rtree.c
+++ b/third_party/sqlite/src/ext/rtree/rtree.c
@@ -2877,7 +2877,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
int rc; /* Return code */
RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */
int iCell; /* Index of iDelete cell in pLeaf */
- RtreeNode *pRoot; /* Root node of rtree structure */
+ RtreeNode *pRoot = 0; /* Root node of rtree structure */
/* Obtain a reference to the root node to initialize Rtree.iDepth */
@@ -3438,7 +3438,7 @@ static int getNodeSize(
if( rc!=SQLITE_OK ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}else if( pRtree->iNodeSize<(512-64) ){
- rc = SQLITE_CORRUPT;
+ rc = SQLITE_CORRUPT_VTAB;
*pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"",
pRtree->zName);
}
diff --git a/third_party/sqlite/src/ext/rtree/rtreeA.test b/third_party/sqlite/src/ext/rtree/rtreeA.test
index 6dc9609..9318463 100644
--- a/third_party/sqlite/src/ext/rtree/rtreeA.test
+++ b/third_party/sqlite/src/ext/rtree/rtreeA.test
@@ -228,6 +228,10 @@ do_execsql_test rtreeA-7.100 {
do_catchsql_test rtreeA-7.110 {
SELECT * FROM t1 WHERE x1>0 AND x1<100 AND x2>0 AND x2<100;
} {1 {undersize RTree blobs in "t1_node"}}
+do_test rtreeA-7.120 {
+ sqlite3_extended_errcode db
+} {SQLITE_CORRUPT_VTAB}
+
finish_test
diff --git a/third_party/sqlite/src/ext/rtree/rtreeconnect.test b/third_party/sqlite/src/ext/rtree/rtreeconnect.test
new file mode 100644
index 0000000..133efbd
--- /dev/null
+++ b/third_party/sqlite/src/ext/rtree/rtreeconnect.test
@@ -0,0 +1,56 @@
+# 2017 August 17
+#
+# 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.
+#
+#***********************************************************************
+#
+# The focus of this file is testing the r-tree extension. Specifically,
+# the impact of an SQLITE_SCHEMA error within the rtree module xConnect
+# callback.
+#
+
+
+if {![info exists testdir]} {
+ set testdir [file join [file dirname [info script]] .. .. test]
+}
+source $testdir/tester.tcl
+set testprefix rtreeconnect
+
+ifcapable !rtree {
+ finish_test
+ return
+}
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE r1 USING rtree(id, x1, x2, y1, y2);
+ CREATE TABLE t1(id, x1, x2, y1, y2);
+ CREATE TABLE log(l);
+
+ CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
+ INSERT INTO r1 VALUES(new.id, new.x1, new.x2, new.y1, new.y2);
+ INSERT INTO log VALUES('r1: ' || new.id);
+ END;
+}
+
+db close
+sqlite3 db test.db
+sqlite3 db2 test.db
+
+do_test 1.1 {
+ db eval { INSERT INTO log VALUES('startup'); }
+ db2 eval { CREATE TABLE newtable(x,y); }
+} {}
+
+do_execsql_test 1.2 {
+ INSERT INTO t1 VALUES(1, 2, 3, 4, 5);
+}
+
+db2 close
+db close
+
+finish_test
diff --git a/third_party/sqlite/src/ext/session/sqlite3session.h b/third_party/sqlite/src/ext/session/sqlite3session.h
index 0bb362e..b3df6d7 100644
--- a/third_party/sqlite/src/ext/session/sqlite3session.h
+++ b/third_party/sqlite/src/ext/session/sqlite3session.h
@@ -375,8 +375,8 @@ int sqlite3session_diff(
*/
int sqlite3session_patchset(
sqlite3_session *pSession, /* Session object */
- int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
- void **ppPatchset /* OUT: Buffer containing changeset */
+ int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */
+ void **ppPatchset /* OUT: Buffer containing patchset */
);
/*
@@ -1143,12 +1143,12 @@ int sqlite3changeset_apply(
**
** <table border=1 style="margin-left:8ex;margin-right:8ex">
** <tr><th>Streaming function<th>Non-streaming equivalent</th>
-** <tr><td>sqlite3changeset_apply_str<td>[sqlite3changeset_apply]
-** <tr><td>sqlite3changeset_concat_str<td>[sqlite3changeset_concat]
-** <tr><td>sqlite3changeset_invert_str<td>[sqlite3changeset_invert]
-** <tr><td>sqlite3changeset_start_str<td>[sqlite3changeset_start]
-** <tr><td>sqlite3session_changeset_str<td>[sqlite3session_changeset]
-** <tr><td>sqlite3session_patchset_str<td>[sqlite3session_patchset]
+** <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply]
+** <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
diff --git a/third_party/sqlite/src/main.mk b/third_party/sqlite/src/main.mk
index 908cf51..5c34a8d 100644
--- a/third_party/sqlite/src/main.mk
+++ b/third_party/sqlite/src/main.mk
@@ -55,7 +55,8 @@ THREADLIB += $(LIBS)
LIBOBJ+= vdbe.o parse.o \
alter.o analyze.o attach.o auth.o \
backup.o bitvec.o btmutex.o btree.o build.o \
- callback.o complete.o ctime.o date.o dbstat.o delete.o expr.o \
+ callback.o complete.o ctime.o \
+ date.o dbpage.o dbstat.o delete.o expr.o \
fault.o fkey.o \
fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \
fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \
@@ -98,6 +99,7 @@ SRC = \
$(TOP)/src/complete.c \
$(TOP)/src/ctime.c \
$(TOP)/src/date.c \
+ $(TOP)/src/dbpage.c \
$(TOP)/src/dbstat.c \
$(TOP)/src/delete.c \
$(TOP)/src/expr.c \
@@ -148,7 +150,7 @@ SRC = \
$(TOP)/src/rowset.c \
$(TOP)/src/select.c \
$(TOP)/src/status.c \
- $(TOP)/src/shell.c \
+ $(TOP)/src/shell.c.in \
$(TOP)/src/sqlite.h.in \
$(TOP)/src/sqlite3ext.h \
$(TOP)/src/sqliteInt.h \
@@ -272,6 +274,7 @@ SRC += \
opcodes.h \
parse.c \
parse.h \
+ shell.c \
sqlite3.h
@@ -307,6 +310,7 @@ TESTSRC = \
$(TOP)/src/test_intarray.c \
$(TOP)/src/test_journal.c \
$(TOP)/src/test_malloc.c \
+ $(TOP)/src/test_md5.c \
$(TOP)/src/test_multiplex.c \
$(TOP)/src/test_mutex.c \
$(TOP)/src/test_onefile.c \
@@ -319,6 +323,7 @@ TESTSRC = \
$(TOP)/src/test_sqllog.c \
$(TOP)/src/test_superlock.c \
$(TOP)/src/test_syscall.c \
+ $(TOP)/src/test_tclsh.c \
$(TOP)/src/test_tclvar.c \
$(TOP)/src/test_thread.c \
$(TOP)/src/test_vfs.c \
@@ -336,6 +341,7 @@ TESTSRC += \
$(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/fuzzer.c \
$(TOP)/ext/misc/ieee754.c \
+ $(TOP)/ext/misc/mmapwarm.c \
$(TOP)/ext/misc/nextchar.c \
$(TOP)/ext/misc/percentile.c \
$(TOP)/ext/misc/regexp.c \
@@ -360,6 +366,7 @@ TESTSRC2 = \
$(TOP)/src/btree.c \
$(TOP)/src/build.c \
$(TOP)/src/date.c \
+ $(TOP)/src/dbpage.c \
$(TOP)/src/dbstat.c \
$(TOP)/src/expr.c \
$(TOP)/src/func.c \
@@ -483,6 +490,8 @@ SHELL_OPT += -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5
SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
+SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
+SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
@@ -499,9 +508,9 @@ libsqlite3.a: $(LIBOBJ)
$(AR) libsqlite3.a $(LIBOBJ)
$(RANLIB) libsqlite3.a
-sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h
+sqlite3$(EXE): shell.c libsqlite3.a sqlite3.h
$(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \
- $(TOP)/src/shell.c $(SHELL_ICU) libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
+ shell.c $(SHELL_ICU) libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB)
sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h
$(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \
@@ -610,6 +619,11 @@ lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
$(BCC) -o lemon $(TOP)/tool/lemon.c
cp $(TOP)/tool/lempar.c .
+# A tool to generate the source-id
+#
+mksourceid: $(TOP)/tool/mksourceid.c
+ $(BCC) -o mksourceid $(TOP)/tool/mksourceid.c
+
# Rules to build individual *.o files from generated *.c files. This
# applies to:
#
@@ -649,13 +663,23 @@ parse.c: $(TOP)/src/parse.y lemon $(TOP)/tool/addopcodes.tcl
mv parse.h parse.h.temp
tclsh $(TOP)/tool/addopcodes.tcl parse.h.temp >parse.h
-sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION $(TOP)/ext/rtree/sqlite3rtree.h
+sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid $(TOP)/VERSION $(TOP)/ext/rtree/sqlite3rtree.h
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
$(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c
./mkkeywordhash >keywordhash.h
+# Source files that go into making shell.c
+SHELL_SRC = \
+ $(TOP)/src/shell.c.in \
+ $(TOP)/ext/misc/shathree.c \
+ $(TOP)/ext/misc/fileio.c \
+ $(TOP)/ext/misc/completion.c
+
+shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl
+ tclsh $(TOP)/tool/mkshellc.tcl >shell.c
+
# Rules to build the extension objects.
@@ -757,17 +781,11 @@ sqlite3rbu.o: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR)
# Rules for building test programs and for running tests
#
tclsqlite3: $(TOP)/src/tclsqlite.c libsqlite3.a
- $(TCCX) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite3 \
+ $(TCCX) $(TCL_FLAGS) -DTCLSH -o tclsqlite3 \
$(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) $(THREADLIB)
-sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl
- echo "#define TCLSH 2" > $@
- echo "#define SQLITE_ENABLE_DBSTAT_VTAB 1" >> $@
- cat sqlite3.c $(TOP)/src/tclsqlite.c >> $@
- echo "static const char *tclsh_main_loop(void){" >> $@
- echo "static const char *zMainloop = " >> $@
- tclsh $(TOP)/tool/tostr.tcl $(TOP)/tool/spaceanal.tcl >> $@
- echo "; return zMainloop; }" >> $@
+sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/sqlite3_analyzer.c.in $(TOP)/tool/mkccode.tcl
+ tclsh $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
sqlite3_analyzer$(EXE): sqlite3_analyzer.c
$(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS) $(THREADLIB)
@@ -783,22 +801,24 @@ TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
+TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
+TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
TESTFIXTURE_FLAGS += -DDEFAULT_ENABLE_RECOVER=1
testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
- $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
+ $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
$(TESTSRC) $(TESTSRC2) $(TOP)/src/tclsqlite.c \
-o testfixture$(EXE) $(LIBTCL) libsqlite3.a $(THREADLIB)
amalgamation-testfixture$(EXE): sqlite3.c $(TESTSRC) $(TOP)/src/tclsqlite.c \
$(TOP)/ext/session/test_session.c
- $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
+ $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
$(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c \
$(TOP)/ext/session/test_session.c \
-o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c
- $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
+ $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \
-DSQLITE_ENABLE_FTS3=1 \
$(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts3amal.c \
-o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
diff --git a/third_party/sqlite/src/manifest b/third_party/sqlite/src/manifest
index b2cfcf0..f490a67d 100644
--- a/third_party/sqlite/src/manifest
+++ b/third_party/sqlite/src/manifest
@@ -1,17 +1,17 @@
-C Allow\sindexes\sto\sbe\screated\son\sdate/time\sfunctions\sas\slong\sas\sthe\s'now'\ndate\sand\sthe\s'localtime'\sand\s'utc'\smodifiers\sare\snot\sused.
-D 2017-07-19T19:48:40.351
-F Makefile.in d9873c9925917cca9990ee24be17eb9613a668012c85a343aef7e5536ae266e8
+C Version\s3.21.0
+D 2017-10-24T18:55:49.833
+F Makefile.in e016061b23e60ac9ec27c65cb577292b6bde0307ca55abd874ab3487b3b1beb2
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
-F Makefile.msc 02b469e9dcd5b7ee63fc1fb05babc174260ee4cfa4e0ef2e48c3c6801567a016
+F Makefile.msc 37740aba9c4bb359c627eadccf1cfd7be4f5f847078723777ea7763969e533b1
F README.md f5c87359573c4d255425e588a56554b50fdcc2afba4e017a2e02a43701456afd
-F VERSION 87f1498f27e398bce3da2fa8125c9879a38ed9d87e4b5fb922b351de1e25cadb
+F VERSION f81232df28e2d3ff049feefad5fbd5489cc33697f6bd2ecf61af7f0dde3b83d0
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
-F autoconf/Makefile.am 1a47d071e3d5435f8f7ebff7eb6703848bbd65d4
-F autoconf/Makefile.msc 1014be616b420a5f48611d21b62ca2f50ec97ee795087ecb8a4d6bf6375ba11d
+F autoconf/Makefile.am 66c0befa511f0d95ba229e180067cf0357a9ebf8b3201b06d683c5ba6220fb39
+F autoconf/Makefile.msc 645b8a9774281515dc4a8de65d8a914f7b418ba8bd1c48b53ccbf43d3b339715
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
F autoconf/configure.ac 2893b823ecc86cea13739f6c8109a41392254d1db08235c5615e0af5722c8578
@@ -30,10 +30,10 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
-F configure 1bcc61cdd063171d8945551c265e5701a770deeff77e0ad634f8d22e4e91c831 x
-F configure.ac 13f45f02e6c51dd0e347315b5401c3f047712b7f79b7f35619115c23755afcff
+F configure e9dbb65b61c36bb9622225de254b768d4816749ff4cb4d71307bb067095aceec x
+F configure.ac 369ebae6c04d9d2de5064e21d300f2f42f2fbf13235cabff9d1a54f2b2c4d05d
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
-F doc/lemon.html 1f8b8d4c9f5cfe40e679fee279cc9eb2da8e6eb74ad406028538d7864cc4b6cb
+F doc/lemon.html 278113807f49d12d04179a93fab92b5b917a08771152ca7949d34e928efa3941
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
@@ -114,7 +114,7 @@ F ext/fts5/fts5_test_tok.c ffd657dd67e7fcdb31bf63fb60b6d867299a581d0f46e97086aba
F ext/fts5/fts5_tokenize.c 2ce7b44183538ec46b7907726262ee43ffdd39a8
F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf
F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
-F ext/fts5/fts5_vocab.c e44fefa7f0c1db252998af071daf06a7147e17e7
+F ext/fts5/fts5_vocab.c 1cd79854cb21543e66507b25b0578bc1b20aa6a1349b7feceb8e8fed0e7a77a6
F ext/fts5/fts5parse.y a070b538e08ae9e2177d15c337ed2a3464408f0f886e746307098f746efd94ca
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
F ext/fts5/test/fts5_common.tcl b01c584144b5064f30e6c648145a2dd6bc440841
@@ -140,6 +140,7 @@ F ext/fts5/test/fts5colset.test a30473451321bbf0b6218af62e96b4ae5fa99931cfdb210b
F ext/fts5/test/fts5columnsize.test 45459ce4dd9fd853b6044cdc9674921bff89e3d840f348ca8c1630f9edbf5482
F ext/fts5/test/fts5config.test 60094712debc59286c59aef0e6cf511c37d866802776a825ce437d26afe0817f
F ext/fts5/test/fts5conflict.test 655925678e630d3cdf145d18725a558971806416f453ac8410ca8c04d934238d
+F ext/fts5/test/fts5connect.test b12a2a8b02af3c31c18abbc33aa8100d364de19a888a44457484d21dbccb18a7
F ext/fts5/test/fts5content.test 688d5ac7af194ebc67495daea76a69e3cd5480122c2320e72d41241b423b4116
F ext/fts5/test/fts5corrupt.test 8957f0f7e57e0f8a102c5b6e1a7326d6a1966b28e1d99c5883822af1e6038e9e
F ext/fts5/test/fts5corrupt2.test 6deaf9f9606b3c957529db9881622bb3a7829b19bb3cdf8f276f074d684ede56
@@ -201,13 +202,14 @@ F ext/fts5/test/fts5unindexed.test 9021af86a0fb9fc616f7a69a996db0116e7936d0db638
F ext/fts5/test/fts5update.test 0737876e20e97a6a6abf45de19fc99315727bcee6a83fadcada1cc080b9aa8f0
F ext/fts5/test/fts5version.test 99b81372630fbf359107c96580fa761e41cdfb1dafc9966e148629ca72efee71
F ext/fts5/test/fts5vocab.test 2ba98bcef0fcab3e5fead8eaabd6c0efb7e57bfe707a5cfcc18572ca9b277360
+F ext/fts5/test/fts5vocab2.test 2beeec974a305a1d79b91426622cc922c87065874437d22b400de7438979959e
F ext/fts5/tool/fts5speed.tcl b0056f91a55b2d1a3684ec05729de92b042e2f85
F ext/fts5/tool/fts5txt2db.tcl 526a9979c963f1c54fd50976a05a502e533a4c59
F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
F ext/fts5/tool/mkfts5c.tcl d1c2a9ab8e0ec690a52316f33dd9b1d379942f45
F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
-F ext/icu/icu.c 84900472a088a3a172c6c079f58a1d3a1952c332
+F ext/icu/icu.c 635775226d07c743c770888a9dd5175afc6e67d3e28a4032b7fedc3bcaa92e65
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/lsm1/Makefile 2951812df1c1cbc9e023af7e070876f479b3d75ce3898b3b9d00f83fecf13608
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
@@ -243,16 +245,16 @@ F ext/lsm1/lsm_log.c a8bf334532109bba05b09a504ee45fc393828b0d034ca61ab45e3940709
F ext/lsm1/lsm_main.c 15e73ccdafdd44ddeefc29e332079d88ba8f00c12c797b3c2b63d3171b5afce8
F ext/lsm1/lsm_mem.c 4c51ea9fa285ee6e35301b33491642d071740a0a
F ext/lsm1/lsm_mutex.c 378edf0a2b142b4f7640ee982df06d50b98788ea
-F ext/lsm1/lsm_shared.c 5bc37768e558492f60d7196735ddd54843cd239bd66c1af6eb205a6348ca5e46
+F ext/lsm1/lsm_shared.c 1a76b7a5e89a003c24d58f1fb295c4203b48ef6acba9a194ac6003ade09fcd47
F ext/lsm1/lsm_sorted.c a04518dfbfff0171fafb152a46e9fe9f45e1edbf3570e4533dd58ddb6567f0c9
F ext/lsm1/lsm_str.c 65e361b488c87b10bf3e5c0070b14ffc602cf84f094880bece77bbf6678bca82
F ext/lsm1/lsm_tree.c 682679d7ef2b8b6f2fe77aeb532c8d29695bca671c220b0abac77069de5fb9fb
F ext/lsm1/lsm_unix.c 57361bcf5b1a1a028f5d66571ee490e9064d2cfb145a2cc9e5ddade467bb551b
F ext/lsm1/lsm_varint.c 43f954af668a66c7928b81597c14d6ad4be9fedbc276bbd80f52fa28a02fdb62
-F ext/lsm1/lsm_vtab.c d5af32abe32601b3f2618b9488225db9ca06af803ddee1aaaf1653e08e9d112b
+F ext/lsm1/lsm_vtab.c 529255dc704289001b225d97e57e0cfa14b29c3f281c7349cfa8fdb655de79ae
F ext/lsm1/lsm_win32.c 0a4acbd7e8d136dd3a5753f0a9e7a9802263a9d96cef3278cf120bcaa724db7c
F ext/lsm1/test/lsm1_common.tcl 5ed4bab07c93be2e4f300ebe46007ecf4b3e20bc5fbe1dedaf04a8774a6d8d82
-F ext/lsm1/test/lsm1_simple.test 3bb38951450cd1f12a6c294949334d6fbb109a3da38c48eaf0877a37c43a0fab
+F ext/lsm1/test/lsm1_simple.test ca949efefa102f4644231dcd9291d8cda7699a4ce1006b26e0e3fcb72233f422
F ext/misc/README.md 8e008c8d2b02e09096b31dfba033253ac27c6c06a18aa5826e299fa7601d90b2
F ext/misc/amatch.c 6db4607cb17c54b853a2d7c7c36046d004853f65b9b733e6f019d543d5dfae87
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
@@ -260,7 +262,7 @@ F ext/misc/carray.c 880684b2796ef6ad915094093297eede40db6c07f280c7f491c8eff72ea0
F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
F ext/misc/completion.c 52c3f01523e3e387eb321b4739a89d1fe47cbe6025aa1f2d8d3685e9e365df0f
F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
-F ext/misc/csv.c d91c0388445b08f6e373dd0e8fc024d4551b1fcaf64e876a1c3f4fac8a63adc2
+F ext/misc/csv.c 1a009b93650732e22334edc92459c4630b9fa703397cbb3c8ca279921a36ca11
F ext/misc/dbdump.c 3509fa6b8932d04e932d6b6b827b6a82ca362781b8e8f3c77336f416793e215e
F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
F ext/misc/fileio.c b1aa06c0f1dac277695d4529e5e976c65ab5678dcbb53a0304deaa8adc44b332
@@ -268,27 +270,29 @@ F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
F ext/misc/json1.c dbe086615b9546c156bf32b9378fc09383b58bd17513b866cfd24c1e15281984
F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33
+F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
F ext/misc/regexp.c a68d25c659bd2d893cd1215667bbf75ecb9dc7d4
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
F ext/misc/scrub.c 1c5bfb8b0cd18b602fcb55755e84abf0023ac2fb
-F ext/misc/series.c b0f5f346aca9b7ff7caaf0da2efb4ad462441abd4dcd92a460cb573b3ea2370b
+F ext/misc/series.c f3c0dba5c5c749ce1782b53076108f87cf0b71041eb6023f727a9c50681da564
F ext/misc/sha1.c 0b9e9b855354910d3ca467bf39099d570e73db56
F ext/misc/shathree.c fa185d7aee0ad0aca5e091b4a2db7baff11796170e5793b5de99e511a13af448
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
F ext/misc/spellfix.c a4723b6aff748a417b5091b68a46443265c40f0d
F ext/misc/stmt.c 6f16443abb3551e3f5813bb13ba19a30e7032830015b0f92fe0c0453045c0a11
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
-F ext/misc/unionvtab.c 56fd163d2b6d2f4df0078be482fc9a874658ce51cce33f180c08834193449c78
+F ext/misc/unionvtab.c 1e0ebc5078e1a916db191bcd88f87e94ea7ba4aa563ee30ff706261cb4b39461
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
F ext/misc/vfsstat.c bf10ef0bc51e1ad6756629e1edb142f7a8db1178
+F ext/misc/vtablog.c 31d0d8f4406795679dcd3a67917c213d3a2a5fb3ea5de35f6e773491ed7e13c9
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
F ext/rbu/rbu.c ea7d1b7eb44c123a2a619332e19fe5313500705c4a58aaa1887905c0d83ffc2e
F ext/rbu/rbu1.test 43836fac8c7179a358eaf38a8a1ef3d6e6285842
-F ext/rbu/rbu10.test 046b0980041d30700464a800bbf6733ed2df515d
+F ext/rbu/rbu10.test 1846519a438697f45e9dcb246908af81b551c29e1078d0304fae83f1fed7e9ee
F ext/rbu/rbu11.test 9bc68c2d3dbeb1720153626e3bd0466dcc017702
F ext/rbu/rbu12.test bde22ed0004dd5d1888c72a84ae407e574aeae16
F ext/rbu/rbu13.test 462ff799c4afedc3ef8a47ff818c0ffbf14ae4f2
@@ -307,21 +311,28 @@ F ext/rbu/rbucrash.test 61470d977a06a0abc2ec35b05d82a1d7d87d10f4ffabad14c1c231ed
F ext/rbu/rbucrash2.test b2ecbdd7bb72c88bd217c65bd00dafa07f7f2d4d
F ext/rbu/rbudiff.test 3e605cf624d00d04d0fb1316a3acec4fbe3b3ac5
F ext/rbu/rbudor.test 99b05cc0df613e962c2c8085cfb05686a09cf315
-F ext/rbu/rbufault.test cc0be8d5d392d98b0c2d6a51be377ea989250a89
+F ext/rbu/rbufault.test 2654aef20f8ee7de37c9c1997a44f2773dc7bf24887adea39fb19314ef32cb90
F ext/rbu/rbufault2.test 9a7f19edd6ea35c4c9f807d8a3db0a03a5670c06
-F ext/rbu/rbufault3.test 54a399888ac4af44c68f9f58afbed23149428bca
+F ext/rbu/rbufault3.test 0913c1aeaee266d9c36c33179341a5a504aad7d423d1979cfec43c8346a29899
F ext/rbu/rbufault4.test 34e70701cbec51571ffbd9fbf9d4e0f2ec495ca7
-F ext/rbu/rbufts.test 828cd689da825f0a7b7c53ffc1f6f7fdb6fa5bda
+F ext/rbu/rbufts.test a2bbd202c9321fba15fb4a62a90add7d70e07bd8404e1e598135adbfff8a0508
F ext/rbu/rbuprogress.test 1849d4e0e50616edf5ce75ce7db86622e656b5cf
F ext/rbu/rburesume.test 8acb77f4a422ff55acfcfc9cc15a5cb210b1de83
F ext/rbu/rbusave.test 0f43b6686084f426ddd040b878426452fd2c2f48
+F ext/rbu/rbutemplimit.test cd553a9288d515d0b5f87d277e76fd18c4aa740b761e7880fab11ce986ea18d1
F ext/rbu/rbuvacuum.test ff357e9b556ca7ad4673da0ff7f244def919ff858e0f9f350d3e30fdd83a62a8
F ext/rbu/rbuvacuum2.test 2074ab14fe66e1c7e7210c62562650dcd215bbaa
-F ext/rbu/sqlite3rbu.c d1438580a451eebda3bfd42ef69b677512f00125285e0e4e789b6131a45f6dd8
-F ext/rbu/sqlite3rbu.h fc25e1fcd99b5c6d32b1b5b1c73122632e873ac89bd0be9bf646db362b7ce02c
-F ext/rbu/test_rbu.c ec18cfc69a104309df23c359e3c80306c9a6bdd1d2c53c8b70ae158e9832dcd6
+F ext/rbu/sqlite3rbu.c 64bd08c1011456f90564ed167abce3a9c2af421a924b21eb57231e078da04feb
+F ext/rbu/sqlite3rbu.h b42bcd4d8357268c6c39ab2a60b29c091e89328fa8cc49c8fac5ab8d007e79b2
+F ext/rbu/test_rbu.c 7073979b9cc80912bb03599ac8d85ab5d3bf03cfacd3463f2dcdd7822997533a
+F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
+F ext/repair/checkfreelist.c 0abb84b4545016d57ba1a2aa8884c72c73ed838968909858c03bc1f38fb6b054
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
+<<<<<<< HEAD
F ext/rtree/rtree.c c5886d4ba7e7c66d0f9ee0b788d5532f8537ca04db19cec7f2f64dcf46e9be37
+=======
+F ext/rtree/rtree.c f2fd34db37ea053798f8e66b44a473449b21301d2b92505ee576823789e909fb
+>>>>>>> 8a87f7e... sqlite: Upgrade from 3.20.1 to 3.21.0.
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test 4fdd60ae034e43f2fefc26492032d02e742e8b14d468b7c51d95a1e2fa47cf00
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
@@ -332,7 +343,7 @@ F ext/rtree/rtree6.test 773a90db2dce6a8353dd0d5b64bca69b29761196
F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
F ext/rtree/rtree8.test 076d9d5b783b61b7a23a5ab45fc899551dfffd821974f36ee599ff29f4de7a61
F ext/rtree/rtree9.test 8bfa84dfaba1c897468a2448c28db0a00ad12d464225b5993c7814e907f3776f
-F ext/rtree/rtreeA.test e25d76c1701f8591e7a0b6de8224d5dbc1418c562654c7240e6f33f37b1e36f7
+F ext/rtree/rtreeA.test c09ad3f76c08feac00770685ff50ca12966dc0c641bf19a982b26a80643b46d1
F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e
F ext/rtree/rtreeC.test c0a9c67f2efa98b6fae12acb8a28348d231a481d
F ext/rtree/rtreeD.test fe46aa7f012e137bd58294409b16c0d43976c3bb92c8f710481e577c4a1100dc
@@ -341,6 +352,7 @@ F ext/rtree/rtreeF.test 66deb9fd1611c7ca2e374adba63debdc2dbb12b4
F ext/rtree/rtreeG.test 3b185719630795f38594f64cd7d1de86a33f91f1
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
+F ext/rtree/rtreeconnect.test 225ad3fcb483d36cbee423a25052a6bbae762c9576ae9268332360c68c170d3d
F ext/rtree/sqlite3rtree.h 9c5777af3d2921c7b4ae4954e8e5697502289d28
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
@@ -368,7 +380,7 @@ F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
F ext/session/sessionfault2.test 04aa0bc9aa70ea43d8de82c4f648db4de1e990b0
F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc
F ext/session/sqlite3session.c cc127222a9ea6f4eaa31281aa9da924f5244f6099be0ee526c950684fb3513a6
-F ext/session/sqlite3session.h d4db650adfcc7a4360e9f12a09c2d117b1db6b53
+F ext/session/sqlite3session.h cb4d860101ba6d3ac810f18684539b766d24d668fa2436cdde90d711af9464fb
F ext/session/test_session.c eb0bd6c1ea791c1d66ee4ef94c16500dad936386
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
@@ -376,7 +388,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 5b7d72ab03dd70aa1401f934d31e85aefd6fc542eb58094d7a95d6921390b2d0
+F main.mk a39528d993afc1f0c0aebde2e3623ab4171d3bba484eea1e5241615c706c9ce8
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -388,13 +400,14 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
-F src/alter.c 850ede4e607f12fa25ea4f3cb6ece2b2e29d1aa50e3f786ce49d615788849552
+F src/alter.c cf7a8af45cb0ace672f47a1b29ab24092a9e8cd8d945a9974e3b5d925f548594
F src/analyze.c 0d0ccf7520a201d8747ea2f02c92c26e26f801bc161f714f27b9f7630dde0421
-F src/attach.c 3bd555e28382603e80d430dfebb2270f86e1e375b4c4be3e1ab1aec3a0c44943
-F src/auth.c 79f96c6f33bf0e5da8d1c282cee5ebb1852bb8a6ccca3e485d7c459b035d9c3c
+F src/attach.c 07b706e336fd3cedbd855e1f8266d10e82fecae07daf86717b5760cd7784c584
+F src/auth.c 6277d63837357549fe14e723490d6dc1a38768d71c795c5eb5c0f8a99f918f73
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
+<<<<<<< HEAD
F src/btree.c f55ea8f456d103328d61076be40fa39acbfea05eaa4eccfed275532a63c867c4
F src/btree.h 3edc5329bc59534d2d15b4f069a9f54b779a7e51289e98fa481ae3c0e526a5ca
F src/btreeInt.h 97700795edf8a43245720414798b7b29d8e465aef46bf301ffacd431910c0da1
@@ -406,25 +419,43 @@ F src/date.c 921fb5957cacfb4e512d25efa13fbdf5f3ebade2077a0809fbe24105d2f33cff
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
F src/delete.c 939bd15e6b54b82b951e1c0ffc2ff2b4ab579196780a1f6d394e47bd6f799b6c
F src/expr.c 17fb28516a5fbfbabdade6b3401c797b0804de25e36b7b1becff2cf07921dc4c
+=======
+F src/btree.c 75229a5a47985997f861b428552acd14fe42b657f755cba5e0b1a007bd77b2ea
+F src/btree.h 32ef5d3f25dc70ef1ee9cecf84a023c21378f06a57cd701d2e866e141b150f09
+F src/btreeInt.h 55b702efce17e5d1941865464227d3802cfc9c7c832fac81d4c94dced47a71fc
+F src/build.c e24b61144f9c9b15c4aa05954514190361061da721e56dcd1af6e0e945ee5909
+F src/callback.c 28a8ede982fde4129b828350f78f2c01fe7d12c74d1a0a05d7108ab36f308688
+F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
+F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
+F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
+F src/dbpage.c c625a0bd605d4cea9a3258b8db49a5474a04976e95a9fe380cdaf74e8eb6736d
+F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
+F src/delete.c 21a5f1812fdb599e9f7afb9f650bdabab60a3afd51d7e94e539c982f647b0023
+F src/expr.c 755caeafc43e3cd31e1d810795712641f6e19f7e7e9575faece4c77381fd8304
+>>>>>>> 8a87f7e... sqlite: Upgrade from 3.20.1 to 3.21.0.
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 5ff2c895fe087756d8085dc1a9bc229b5670e2a65c3929dd87c71e43649af333
-F src/func.c e2854b19386b93ad6b498a3f3b7d6baa98ec14cfe84530fb12fce4414263d871
-F src/global.c 8a6ab6b4d91effb96ffa81b39f0d70c862abca157f8aaa194600a4a8b7923344
+F src/func.c b4d259af627e3cd9510cf08db37f0bcc88b1887c735169c74490c3739d5cf5c6
+F src/global.c ac3094f1dc59fbeb919aef7cc0cc827a8459d1fb1adb7972ef75bd9e0c10b75b
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
+<<<<<<< HEAD
F src/insert.c bb70abf32c7c926745eb550938db9132309584a667a44c2db0e5fa3207600391
+=======
+F src/insert.c 1f33ef4ca0553b60fff03aa171370f8709a3e945acfcc68ccafc92752d872f40
+>>>>>>> 8a87f7e... sqlite: Upgrade from 3.20.1 to 3.21.0.
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
F src/loadext.c 20865b183bb8a3723d59cf1efffc3c50217eb452c1021d077b908c94da26b0b2
-F src/main.c 3a9da9e3974d8a32ef6ca15b75503d540af22d284beb75bc7f0d93254ca3f8f7
-F src/malloc.c e20bb2b48abec52d3faf01cce12e8b4f95973755fafec98d45162dfdab111978
+F src/main.c 54637b9e7f91de6d281e577cd1a997762a4613f51a0509790027ca9865185d7c
+F src/malloc.c a02c9e69bc76bee0f639416b947a946412890b606301454727feadcb313536d6
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
-F src/memjournal.c 95752936c11dc6995672d1dd783cd633eea0cc95
+F src/memjournal.c 6f3d36a0a8f72f48f6c3c722f04301ac64f2515435fa42924293e46fc7994661
F src/msvc.h 4942752b6a253116baaa8de75256c51a459a5e81
F src/mutex.c 8e45800ee78e0cd1f1f3fe8e398853307f4a085c
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
@@ -432,13 +463,14 @@ F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
F src/mutex_unix.c 27bb6cc49485ee46711a6580ab7b3f1402211d23
F src/mutex_w32.c a898fa969823b100c0f5fdc57e54c9a1e419ab4d
F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
-F src/os.c add02933b1dce7a39a005b00a2f5364b763e9a24
-F src/os.h 8e976e59eb4ca1c0fca6d35ee803e38951cb0343
+F src/os.c 22d31db3ca5a96a408fbf1ceeaaebcaf64c87024d2ff9fe1cf2ddbec3e75c104
+F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
-F src/os_unix.c 30e2c43e4955db990e5b5a81e901f8aa74cc8820
-F src/os_win.c 2a6c73eef01c51a048cc4ddccd57f981afbec18a
+F src/os_unix.c 3984fc069df59e26f000e30609611cecdb4e93293e6ee52313a473a7e874af1b
+F src/os_win.c 6892c3ff23b7886577e47f13d827ca220c0831bae3ce00eea8c258352692f8c6
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
+<<<<<<< HEAD
F src/pager.c 14f6982c470c05b8e85575c69e9c1712010602e20400f8670d8699e21283e0e4
F src/pager.h f2a99646c5533ffe11afa43e9e0bea74054e4efa
F src/parse.y e384cb73f99e1b074085c974b37f4d830e885359e4b60837e30f7d67c16ba65b
@@ -446,12 +478,22 @@ F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870
F src/pcache.h 521bb9610d38ef17a3cc9b5ddafd4546c2ea67fa3d0e464823d73c2a28d50e11
F src/pcache1.c 1195a21fe28e223e024f900b2011e80df53793f0356a24caace4188b098540dc
F src/pragma.c 95672b7dc59930b4978d08baa8c357085767cc30e5d3ddac9b12592489d3ede2
+=======
+F src/pager.c 07cf850241667874fcce9d7d924c814305e499b26c804322e2261247b5921903
+F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
+F src/parse.y 52ef3cecd0934e9da4a45b585883a03243ad615d338ad94f44501a05891dcdfa
+F src/pcache.c 4bada070456980c3c1f16d58ec2e64e389ad77b935e3d77e0c96e7bbd397289c
+F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
+F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
+F src/pragma.c d04725ac25387d9638919e197fb009f378e13af7bf899516979e54b3164e3602
+>>>>>>> 8a87f7e... sqlite: Upgrade from 3.20.1 to 3.21.0.
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
-F src/prepare.c dd250f904739b1dc449c131ac527c35e3424d94082dd111321bd83f80c6bb0fe
-F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2
+F src/prepare.c 9a141a1b02dca53beaa9771699d390aafcac01f5d1f1c0ae6e23ded8dcdb709a
+F src/printf.c 40aee47ae9be4bd3dbdc8968bd07fddc027be8edec8daddf24d3391d36698a1c
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
-F src/resolve.c 4324a94573b1e29286f8121e4881db59eaedc014afeb274c8d3e07ed282e0e20
+F src/resolve.c 5a461643f294ec510ca615b67256fc3861e4c8eff5f29e5940491e70553b1955
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
+<<<<<<< HEAD
F src/select.c c6bf96a7f9d7d68f929de84738c599a30d0a725ab0b54420e70545743cd5ee7b
F src/shell.c dd4494287b22ac5ab0654fdd5acb1f2172d2fe621f673a39229ddc31bd8d598f
F src/shell.c.in b5725acacba95ccefa57b6d068f710e29ba8239c3aa704628a1902a1f729c175
@@ -459,38 +501,52 @@ F src/sqlite.h.in dad804d4e1979a2ddec33cc8da6aa50c04e6ba0dcb4058e7b3609588d010e0
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 967154985ed2ae62f90d9029bb5b5071793d847f1696a2ebe9e8cc0b042ae60b
F src/sqliteInt.h 9b57e05822422268d5a20fa797afd23bf2b039c8401e87dff26700c0c39faf34
+=======
+F src/select.c e6a068d9ea54417d625578086d3d482284af8d5a449bb3593d40c257080806a8
+F src/shell.c.in f13262c8778f0cd76bf8d9c01bbf5ef66842e6b14e1705cd60d86ab32a6ce69f
+F src/sqlite.h.in ab4f8a29d1580dfaeb6891fa1b83cff8229ba0daa56994707ceaca71495d9ab7
+F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
+F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
+F src/sqliteInt.h 6f93fd6fde862410ac26b930f70752c38ad99ea78c3fc28356bac78049c53bd9
+>>>>>>> 8a87f7e... sqlite: Upgrade from 3.20.1 to 3.21.0.
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
-F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
+F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
-F src/tclsqlite.c 2c29b0b76e91edfd1b43bf135c32c8674710089197327682b6b7e6af88062c3d
-F src/test1.c cfb78b728b37ae3a2b14fe1b3a6c766e0da41370eda112594e698c94011b622e
+F src/tclsqlite.c 1833388c01e3b77f4c712185ee7250b9423ee0981ce6ae7e401e47db0319a696
+F src/test1.c 8ef15f7a357f85dfc41c6c748ce9c947b4f676e01bb5ae6a45bee4923dff8b51
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
-F src/test6.c 004ad42f121f693b8cbe060d1a330678abc61620
+F src/test6.c e8d839fbc552ce044bec8234561a2d5b8819b48e29548ad0ba400471697946a8
F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010
-F src/test8.c 4f4904721167b32f7a4fa8c7b32a07a673d6cc86
+F src/test8.c 3f7d0cc4e12e06832ba3db4455cb16867ccadafa602eb6ff5fcf097bffce56ed
F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
F src/test_async.c 195ab49da082053fdb0f949c114b806a49ca770a
F src/test_autoext.c 915d245e736652a219a907909bb6710f0d587871
F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
+<<<<<<< HEAD
F src/test_bestindex.c d23f80d334c59662af69191854c76b8d3d0c8c96
F src/test_blob.c f65ac717da2618691cf9dad094e6da0219dcd208
+=======
+F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857
+F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
+>>>>>>> 8a87f7e... sqlite: Upgrade from 3.20.1 to 3.21.0.
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
-F src/test_config.c abf6fc1fe9d041b699578c42e3db81f8831c4f5b804f1927958102ee8f2b773e
+F src/test_config.c 3000f00b9b47b149d842059904c3fcab5f3871fb6aee7d7cc5756f0c64779ae3
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
-F src/test_devsym.c 4e58dec2602d8e139ca08659f62a62450587cb58
+F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2
F src/test_fs.c 35a2f7dd8a915900873386331386d9ba1ae1b5026d74fd20c2807bc76221f291
-F src/test_func.c a4fdab3363b436c1b12660e9362ce3f3782b7b5e
+F src/test_func.c d12d805953bcb3bb19f71d29cdc93383b7b7a3369504d2b7e398a1bd77376294
F src/test_hexio.c 1d4469ca61ab202a1fcec6543f584d2407205e8d
F src/test_init.c 4413c211a94b62157ca4c145b3f27c497f03c664
F src/test_intarray.c 988fc61cb0ff539f4172c0d95f15287c92516f64
F src/test_intarray.h f3b7672f5d1056eac563c0d6ea8480a660b1475c
F src/test_journal.c 619f2aa10e0d7a5f87c0f06825bc61dfce1c6b9c7f3ad990fb13de6c3b8874a3
F src/test_loadext.c 337056bae59f80b9eb00ba82088b39d0f4fe6dfd
-F src/test_malloc.c c05f6c40bd6c8bfe5f1718212f81fd5687f91766
+F src/test_malloc.c 4f06a805de86be5216a127b3777ca2d5a1ff99d1a9238374ce136a47411be36c
+F src/test_md5.c 7268e1e8c399d4a5e181b64ac20e1e6f3bc4dd9fc87abac02db145a3d951fa8c
F src/test_multiplex.c e054459f7633f3ff8ce1245da724f9a8be189e4e
F src/test_multiplex.h 5436d03f2d0501d04f3ed50a75819e190495b635
F src/test_mutex.c 7f4337ba23ee6b1d2ec81c189653608cb069926a
@@ -505,7 +561,8 @@ F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
F src/test_sqllog.c 11e6ce7575f489155c604ac4b439f2ac1d3d5aef
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
-F src/test_tclvar.c df9fe1213c2634687a9ca0b0bec0d2119d359ae3
+F src/test_tclsh.c 74fcfb7f3b0ff1f871e62263dd84ffba46a8e9d477439115e0fb2035e4bf69e1
+F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
F src/test_vfs.c f0186261a24de2671d080bcd8050732f0cb64f6e
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
@@ -515,9 +572,10 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
F src/treeview.c 2ee4a5dada213d5ab08a742af5c876cee6f1aaae65f10a61923f3fb63846afef
-F src/trigger.c d1cae560bfacc8bfb3a072d73658245c1714c0389097da69b4cb23877a082d7e
-F src/update.c c443935c652af9365e033f756550b5032d02e1b06eb2cb890ed7511ae0c051dc
+F src/trigger.c 48e0f7ed6749ce4d50a695e09e20ce9cf84ecabf2691852c965a51e0b620eccc
+F src/update.c 5404be9e840717323a69209190cdbc9d0d34adaedaaf1d1a1069babf2c4171c0
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
+<<<<<<< HEAD
F src/util.c fc081ec6f63448dcd80d3dfad35baecfa104823254a815b081a4d9fe76e1db23
F src/vacuum.c 874c0f2f15ab2908748297d587d22d485ea96d55aaec91d4775dddb2e24d2ecf
F src/vdbe.c 1e541ec7ff409bbabcc6b4f154957296fff5827c16c2ab0056348acae75685bf
@@ -530,14 +588,28 @@ F src/vdbemem.c fe8fce1cdc258320b465934039fe4b1230d63f81d6b81b1eac775b6eec00af0d
F src/vdbesort.c f512c68d0bf7e0105316a5594c4329358c8ee9cae3b25138df041d97516c0372
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
F src/vtab.c 35b9bdc2b41de32a417141d12097bcc4e29a77ed7cdb8f836d1d2305d946b61b
+=======
+F src/util.c 5168013cfd937a695d23cce8c67cb07a3dda242d4cb812530ba1148b88e0f159
+F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
+F src/vdbe.c 3393b508d9ad084ffce232a7c53e375ef5ac99b50b685c5131fcdfce97a9d534
+F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97
+F src/vdbeInt.h 1fe00770144c12c4913128f35262d11527ef3284561baaab59b947a41c08d0d9
+F src/vdbeapi.c 9c670ca0dcc1cd86373aa353b747b26fe531ca5cd4331690c611d1f03842e2a1
+F src/vdbeaux.c c423065d50cee24bc8cba57764f5e9869a1bb920c50907f5dd363ebd7c5aef82
+F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
+F src/vdbemem.c 5c1533bf756918b4e46b2ed2bb82c29c7c651e1e37bbd0a0d8731a68787598ff
+F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
+F src/vdbetrace.c 48e11ebe040c6b41d146abed2602e3d00d621d7ebe4eb29b0a0f1617fd3c2f6c
+F src/vtab.c 0e4885495172e1bdf54b12cce23b395ac74ef5729031f15e1bc1e3e6b360ed1a
+>>>>>>> 8a87f7e... sqlite: Upgrade from 3.20.1 to 3.21.0.
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
-F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344
-F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
-F src/walker.c a7ca64ce08a83a20d32186fbe06bca9234e348cfcf07959ee322fdc3e8a6173a
-F src/where.c cbe8ddffbcec7ce86f7a800fe8fd10aee412c76c87e0dd3732a1682e68d74cd9
-F src/whereInt.h 93bb90b77d39901eda31b44d8e90da1351193ccfe96876f89b58a93a33b84c3d
-F src/wherecode.c c0c4c31573486cd14bb2cbfc63e41eda591609e5190416261999f211bf97abc1
-F src/whereexpr.c bf983d2d33e325cd63a36c40b8de289fd3d7b4d9f2db9052fb8f59f7161a34a0
+F src/wal.c 839db09792fead5052bb35e533fa485e134913d547d05b5f42e537b73e63f07a
+F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
+F src/walker.c 3ccfa8637f95355bff61144e01a615b8ef26f79c312880848da73f03367da1e6
+F src/where.c d8c6d690c4b11f30211de073011fe19352364a6303ae053f45cb66f9576ba8a9
+F src/whereInt.h 82c04c5075308abbac59180c8bad5ecb45b07453981f60a53f3c7dee21e1e971
+F src/wherecode.c e8c2ece5843ea56e6c90277d421f2d628f3f7b7c976642369cc519f008e1d2b1
+F src/whereexpr.c afcac9cccfc0fdaccbdda94034a398947b6dc47dbf821c1b496261722832a6a4
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@ -558,7 +630,7 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
F test/analyze6.test f1c552ce39cca4ec922a7e4e0e5d0203d6b3281f
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
F test/analyze8.test c05a461d0a6b05991106467d0c47480f2e709c82
-F test/analyze9.test b817b8e798315fc65b820a5463f73ad5f48ed8dd
+F test/analyze9.test dac0bdc7eab965b9ad639ca83564d98717aaf13ce5a776f23d9a3680238cecd8
F test/analyzeA.test 3335697f6700c7052295cfd0067fc5b2aacddf9a
F test/analyzeB.test a4c1c3048f6d9e090eb76e83eecb18bcf6d31a70
F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93
@@ -572,8 +644,9 @@ F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
F test/atof1.test ff0b0156fd705b67c506e1f2bfe9e26102bea9bd
+F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061
F test/attach.test f4b8918ba2f3e88e6883b8452340545f10a1388af808343c37fc5c577be8281c
-F test/attach2.test 0ec5defa340363de6cd50fd595046465e9aaba2d
+F test/attach2.test 256bd240da1835fb8408dd59fb7ef71f8358c7a756c46662434d11d07ba3a0ce
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
@@ -604,9 +677,11 @@ F test/bestindex1.test 0cf1bd2d7b97d3a3a8c10736125274f64765c4ee
F test/bestindex2.test 4a06b8922ab2fd09434870da8d1cdf525aaf7060
F test/bestindex3.test 578b6a52dab819e63f28e3640e04b32c85aed320
F test/bestindex4.test 4cb5ff7dbaebadb87d366f51969271778423b455
+F test/bestindex5.test 412b42f8036b28d8b2f3534d89389ad946a4b1a65a12263f51936f7424296f1b
F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c
F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59
F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc
+F test/bigmmap.test abe819e6e1ac1db0c3bfe364ff58889d96e7896b2bbc8bdf1afc77cdeb7d7a9b
F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
F test/bigsort.test 8299fa9298f4f1e02fc7d2712e8b77d6cd60e5a2
F test/bind.test 1e136709b306f7ed3192d349c2930d89df6ab621654ad6f1a72381d3fe76f483
@@ -624,7 +699,7 @@ F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
F test/btree01.test e08b3613540145b353f20c81cb18ead54ff12e0f
F test/btree02.test fe69453d474d8154d19b904157ff1db4812fed99
F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
-F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
+F test/busy.test 510dc6daaad18bcbbc085bcc6217d6dc418def5e73f72ce1475eea0cb7834727
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61
F test/cachespill.test 895997f84a25b323b166aecb69baab2d6380ea98f9e0bcc688c4493c535cfab9
@@ -637,6 +712,7 @@ F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef
F test/check.test 33a698e8c63613449d85d624a38ef669bf20331daabebe3891c9405dd6df463a
+F test/checkfreelist.test 100283a3e6b8a3018c7fab7cfdaf03d1d6540fc66453114e248cf82b25784d3b
F test/close.test 799ea4599d2f5704b0a30f477d17c2c760d8523fa5d0c8be4a7df2a8cad787d8
F test/closure01.test b1703ba40639cfc9b295cf478d70739415eec6a4
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
@@ -652,7 +728,11 @@ F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a
F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
F test/collateB.test 1e68906951b846570f29f20102ed91d29e634854ee47454d725f2151ecac0b95
F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
+<<<<<<< HEAD
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
+=======
+F test/colname.test c47639d26cbeba6977457e5ef2c2c55c5b6c889478dd7eb0ed858ba894e7fa93
+>>>>>>> 8a87f7e... sqlite: Upgrade from 3.20.1 to 3.21.0.
F test/conflict.test 029faa2d81a0d1cafb5f88614beb663d972c01db
F test/conflict2.test bb0b94cf7196c64a3cbd815c66d3ee98c2fecd9c
F test/conflict3.test a83db76a6c3503b2fa057c7bfb08c318d8a422202d8bc5b86226e078e5b49ff9
@@ -668,7 +748,7 @@ F test/corrupt8.test 2399dfe40d2c0c63af86706e30f3e6302a8d0516
F test/corrupt9.test 730a3db08d4ab9aa43392ea30d9c2b4879cbff85
F test/corruptA.test 112f4b2ae0b95ebf3ea63718642fb969a93acea557ace3a307234d19c245989b
F test/corruptB.test 73a8d6c0b9833697ecf16b63e3c5c05c945b5dec
-F test/corruptC.test 46ec43bd90a02fd7b37ad8a7a949c55aa5717f89
+F test/corruptC.test 138ecb02188ed1a719b533d4a139568204039f72f00e07a8d30d920bd83122db
F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040
F test/corruptE.test 82ccf4f8f543fdbedd4aa42c709cb077f7374c62
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
@@ -676,7 +756,7 @@ F test/corruptG.test adf79b669cbfd19e28c8191a610d083ae53a6d51
F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
F test/corruptI.test 075fe1d75aa1d84e2949be56b6264376c41502e4
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
-F test/corruptK.test 814a59ec699d8546b4e29005fba3d16e933ef2fe
+F test/corruptK.test 91550557849244a9904f4e090052e3f2c1c3f1106840d58b00ffaa3a8c2d3fc0
F test/cost.test 1eedbfd868f806f3fa08ff072b04cf270dcf61c8
F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c
F test/coveridxscan.test b629e896b14df2f000a99b8d170d80589c46562c
@@ -692,12 +772,13 @@ F test/crashM.test d95f59046fa749b0d0822edf18a717788c8f318d
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
-F test/csv01.test e0ba3caaa57e4c667a0b45977689fb8082f14348
+F test/csv01.test 526fc6aefd052badd5a0283f86b4b395c3df76bfe98d96c801f494f5e2c7836c
F test/ctime.test 78749e6c9a5f0010d67985be80788f841e3cd2da18114e2ed6010399a7d807f3
F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
F test/cursorhint2.test 8457e93d97f665f23f97cdbc8477d16e3480331b
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
+F test/dbpage.test 10b9e91d07b0892444fff4578706648e955b5fb260218298f838da74f0d9d211
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
@@ -722,7 +803,7 @@ F test/e_createtable.test d4c6059d44dcd4b636de9aae322766062b471844
F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
F test/e_dropview.test 21ce09c361227ddbc9819a5608ee2700c276bdd5
-F test/e_expr.test 146deba180273d19e3bf9f6b45f4e50094c64c7ec4756ea72f79dda25818eb17
+F test/e_expr.test ca8896601ade1e27c6559614c7f32c63d44636fdfa720436a160f09b8bf66c89
F test/e_fkey.test dcdc6ad26b1d4f07636208de4c1c22aae7c0597a685a6c10fe6da91f3191dd96
F test/e_fts3.test 8cf40550bb088a6aa187c818c00fabe26ef82900a4cd5c66b427ccafe28bedaa
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
@@ -732,7 +813,7 @@ F test/e_select.test 16651bb681e83a1a2875ff4a595ed2b4b4dee375
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
F test/e_totalchanges.test b12ee5809d3e63aeb83238dd501a7bca7fd72c10
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
-F test/e_uri.test 25385396082b67fd02ae0038b95a3b3575fe0519
+F test/e_uri.test 47eeb2960e74613f0f8722b2f13aef08fde69daa16e5380ac93df84dac8b1f72
F test/e_vacuum.test 1b8b4772d05374aa1b8958669138bbb4213ee26a
F test/e_wal.test ae9a593207a77d711443ee69ffe081fda9243625
F test/e_walauto.test 248af31e73c98df23476a22bdb815524c9dc3ba8
@@ -743,7 +824,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
-F test/eqp.test 3f9ba0b2594837c7beaa3ba824e2137cfe857308f020ec5a0c7a62b444e837b0
+F test/eqp.test 3fe051af50921284189d1970eb653f9fcf5117d2
F test/errmsg.test eae9f091eb39ce7e20305de45d8e5d115b68fa856fba4ea6757b6ca3705ff7f9
F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c
F test/exclusive.test 9a57bd66e39144b888ca75c309914fcdefb4e3f9
@@ -753,7 +834,7 @@ F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
F test/expr.test 66a2c9ac34f74f036faa4092f5402c7d3162fc93
F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
-F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7
+F test/fallocate.test 87b5e43c872b7e69cd80b7b8813eb102b571a75d45dda24e38b65537bcc85733
F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3
F test/filefmt.test f393e80c4b8d493b7a7f8f3809a8425bbf4292af1f5140f01cb1427798a2bbd4
F test/fkey1.test ba64806ff9a04eecab2679caad377ae99a5e94e4
@@ -826,7 +907,7 @@ F test/fts3aux2.test 7ae2b2c13aefdf4169279a27a5f51780ce57f6ba
F test/fts3b.test c15c4a9d04e210d0be67e54ce6a87b927168fbf9c1e3faec8c1a732c366fd491
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
-F test/fts3conf.test 60317efd562080e198b5bdc9fcd222ce32cf01d7
+F test/fts3conf.test c84bbaec81281c1788aa545ac6e78a6bd6cde2bdbbce2da261690e3659f5a76b
F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
F test/fts3corrupt3.test 56e0ee83e90b57f5f3644cb7d1b36a067b7b8b19cdf0dedce45e5e13cf752f65
@@ -854,6 +935,7 @@ F test/fts3offsets.test b85fd382abdc78ebce721d8117bd552dfb75094c
F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2
F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce
F test/fts3query.test f33eb71a1fe1084ea585eeb7ee76b390729f5170
+F test/fts3rank.test e4d2e16a28c98cae95001a75e2b4b05b19b051ffd6aaab15491c5e0595127b9b
F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0
F test/fts3shared.test 57e26a801f21027b7530da77db54286a6fe4997e
F test/fts3snippet.test 01a4231816e03a0660ae53ba2404fe69012fe0db
@@ -901,7 +983,7 @@ F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
-F test/having.test b3d6b17cc9601b6b373b2d0f08c075ccf30e2d307249c3c8a236e3c36907b1a5
+F test/having.test e4098a4b8962f9596035c3b87a8928a10648acc509f1bb8d6f96413bbf79a1b3
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
@@ -935,8 +1017,13 @@ F test/index7.test 7feababe16f2091b229c22aff2bcc1d4d6b9d2bb
F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721
F test/indexedby.test 9c4cd331224e57f79fbf411ae245e6272d415985
+<<<<<<< HEAD
F test/indexexpr1.test 1857373a97e4795ce4119caf05cbb148bdabe1c8738fc0b7e5e240abb6adbe4e
F test/indexexpr2.test 3ddd7f23bc381b9f2b7a15f2d083b1a4078e7733dce8295602ecfa3c74a34cf9
+=======
+F test/indexexpr1.test 84100e880154a4b645db9f4fc7642756d9a2b6011b68f73c8efda4d244816de9
+F test/indexexpr2.test 13247bac49143196556eb3f65e97ef301bd3e993f4511558b5db322ddc370ea6
+>>>>>>> 8a87f7e... sqlite: Upgrade from 3.20.1 to 3.21.0.
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371
@@ -974,10 +1061,10 @@ F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb2848
F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0
F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
-F test/kvtest.c d2b8cfc91047ebf6cac4f3a04f19c3a864e4ecfd683bbb65c395df450b8dc79c
+F test/kvtest.c fcb38ffe3db028a3138b4818fc098359c80dc51a0d1278a91c99c554cc1abb92
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
-F test/like.test 3d26ae14d7042a0e96f7b0b9e9ad2c8ca6ed122772439c6b1c691fe167e15a37
+F test/like.test 11cfd7d4ef8625389df9efc46735ff0b0b41d5e62047ef0f3bc24c380d28a7a6
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
F test/like3.test 3608a2042b6f922f900fbfd5d3ce4e7eca57f7c4
F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e
@@ -992,7 +1079,7 @@ F test/lock5.test c6c5e0ebcb21c61a572870cc86c0cb9f14cede38
F test/lock6.test ad5b387a3a8096afd3c68a55b9535056431b0cf5
F test/lock7.test 49f1eaff1cdc491cc5dee3669f3c671d9f172431
F test/lock_common.tcl 7ffb45accf6ee91c736df9bafe0806a44358f035
-F test/lookaside.test 90052e87282de256d613fcf8c9cbb845e4001d2f
+F test/lookaside.test b17c99ae3aef96a8c9fa6f6be33cc75b93d657cb791d3827302b6835b71941f7
F test/main.test bb75e406c9b64931f3dc7e7f04626633365bb22f
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
F test/malloc.test 21c213365f2cca95ab2d7dc078dc8525f96065f8
@@ -1022,13 +1109,13 @@ F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
F test/memdb.test c1f2a343ad14398d5d6debda6ea33e80d0dafcc7
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
-F test/memsubsys1.test 6d268d0ae90f8d61a2356a1838665654d83de518
+F test/memsubsys1.test 9e7555a22173b8f1c96c281ce289b338fcba2abe8b157f8798ca195bbf1d347e
F test/memsubsys2.test 3e4a8d0c05fd3e5fa92017c64666730a520c7e08
F test/minmax.test 6751e87b409fe11b02e70a306d846fa544e25a41
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f
-F test/misc1.test 6430dabfb4b4fa480633590118964201f94d3ccc
+F test/misc1.test 76737c259537586355f45e2a1e121b6e91b5476c4604ad5c53d1abfcb3acf786
F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
F test/misc4.test 0d8be3466adf123a7791a66ba2bc8e8d229e87f3
@@ -1037,18 +1124,20 @@ F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2
F test/misc8.test ba03aaa08f02d62fbb8d3b2f5595c1b33aa9bbc5
F test/misuse.test 9e7f78402005e833af71dcab32d048003869eca5abcaccc985d4f8dc1d86bcc7
+F test/mjournal.test 68b749956f9a179e7e633a3958b48a5a905d28d30c7ec88f3f26dc6f220129db
F test/mmap1.test d2cfc1635171c434dcff0ece2f1c8e0a658807ce
F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022
F test/mmap3.test b3c297e78e6a8520aafcc1a8f140535594c9086e
F test/mmap4.test 2e2b4e32555b58da15176e6fe750f17c9dcf7f93
F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3
+F test/mmapwarm.test 2272005969cd17a910077bd5082f70bc1fefad9a875afec7fc9af483898ecaf3
F test/multiplex.test dc0d67b66f84b484a83cb8bbdf3f0a7f49562ccd
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
F test/multiplex4.test e8ae4c4bd70606a5727743241f13b5701990abe4
F test/mutex1.test ea2cc74d97f077b9e74c84cbd024f14d79a8126f
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
-F test/nan.test dacc57f80859c06a433d30839336fe227d2038b3
+F test/nan.test 437d40e6d0778b050d7750726c0cbd2c9936b81962926e8f8c48ca698f00f4d1
F test/nockpt.test 9a436a7213ba5ef7a32304998d386d3ea3f76c9d
F test/nolock.test f196cf8b8fbea4e2ca345140a2b3f3b0da45c76e
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
@@ -1070,7 +1159,7 @@ F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da
F test/orderby8.test 23ef1a5d72bd3adcc2f65561c654295d1b8047bd
F test/orderby9.test 87fb9548debcc2cd141c5299002dd94672fa76a3
F test/oserror.test b32dc34f2363ef18532e3a0a7358e3e7e321974f
-F test/ossfuzz.c f5abed3177f719df3c3109901fcdd26b9fb7f581c8da50fc26f3a81ddfb2c2ae
+F test/ossfuzz.c 7f5cc87a0280a5854c1bfa7d5c4d07d34731f08ec34dc9c916aa35ed292b1468
F test/ossshell.c 296ab63067841bd1b1e97b46a0b2af48ee7f69d50d1a723008bee12dd7122622
F test/ovfl.test 199c482696defceacee8c8e0e0ef36da62726b2f
F test/pager1.test 8149b2a8986fee667ab6a8171ab310be19e77ae215bebad0e90c857b0df1935c
@@ -1086,11 +1175,12 @@ F test/parser1.test 391b9bf9a229547a129c61ac345ed1a6f5eb1854
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
-F test/permutations.test 5e2e5439642898e0947ced066ad09b82bd817ddfb83dc71291b4c957efc84b62
-F test/pragma.test f274259d6393b6681eb433beb8dd39a26ec06a4431052a4880b43b84912a3f58
+F test/permutations.test 490e3333b9b1aefb7ebc6e9ab2ae0e382b7dd8713ccc4a2786b0f75467c2ab6b
+F test/pragma.test 7c8cfc328a1717a95663cf8edb06c52ddfeaf97bb0aee69ae7457132e8d39e7d
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
-F test/pragma4.test 6e85b6eab8e61ffc9c7db59d842276674e8e3264
+F test/pragma4.test 3046501bee2f652dc2a4f9c87781e2741361d6864439c8381aba6c3b774b335c
+F test/pragma5.test fd517f42ee847e126afbbbd9fd0fb9e5a4a61a962496a350adb8a22583fbdc37
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
F test/printf2.test 9e6db85f81c63f2367c34a9d7db384088bd374ad
@@ -1110,9 +1200,9 @@ F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8
F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
F test/regexp2.test 40e894223b3d6672655481493f1be12012f2b33c
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
-F test/releasetest.tcl 7bb585433ce7fb2a2c255ae4b5e24f1bc27fe177ec1120f886cc4852f48f5ee9 x
+F test/releasetest.tcl 0b0b3d926e36822ff63b405d683544ce1014303b029f2678bbcf40c162b5f246 x
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
-F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea
+F test/rollback.test f580934279800d480a19176c6b44909df31ce7ad45267ea475a541daa522f3d3
F test/rollback2.test 8435d6ff0f13f51d2a4181c232e706005fa90fc5
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc
@@ -1130,22 +1220,23 @@ F test/rowvalue9.test d8dd2c6ecac432dadaa79e41dc2434f007be1b6b
F test/rowvaluefault.test 7cd9ccc6c2fbdd881672984087aad0491bb75504
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
-F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d
+F test/savepoint.test 1f8a6b1aea9a0d05837adc463d4bf47bd9d0f1c842f1c2a9caccd639baf34bf9
F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
F test/savepoint7.test cde525ea3075283eb950cdcdefe23ead4f700daa
F test/savepointfault.test f044eac64b59f09746c7020ee261734de82bf9b2
-F test/scanstatus.test 5253c219e331318a437f436268e0e82345700285
+F test/scanstatus.test 1ba0e2ee25dcd1d55ec770803b19832cffaecbf0b15d376807759ebeed3669b0
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
F test/schema4.test 3b26c9fa916abb6dadf894137adcf41b7796f7b9
F test/schema5.test 29699b4421f183c8f0e88bd28ce7d75d13ea653e
+F test/schema6.test e4bd1f23d368695eb9e7b51ef6e02ca0642ea2ab4a52579959826b5e7dce1f9b
F test/securedel.test 5f997cb6bd38727b81e0985f53ec386c99db6441b2b9e6357240649d29017239
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
-F test/select1.test be62204d2bd9a5a8a149e9974cfddce893d8f686
+F test/select1.test 460a5824df01575b18f7fa4bd8e40d09de20c542e90c1543e164bc7d3b0a0bb7
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
F test/select4.test 5389d9895968d1196c457d59b3ee6515d771d328
@@ -1192,7 +1283,7 @@ F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b
F test/snapshot.test 85735bd997a4f6d710140c28fd860519a299649f
-F test/snapshot2.test 867652ed4a13282dce218723535fad1c7b44c3c4
+F test/snapshot2.test 925e42427e923262db63c9d7155183f889e3e99feaedec4075f659e51608344f
F test/snapshot_fault.test 52c5e97ebd218846a8ae2da4d147d3e77d71f963
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087
@@ -1210,7 +1301,7 @@ F test/speed3.test 694affeb9100526007436334cf7d08f3d74b85ef
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
-F test/speedtest1.c 7b1ab42b097b484c18d99e1d1c71a6a0c9c87a7a
+F test/speedtest1.c e44c5fccddcfe916c3bf7fe2f87dcc4b4fd66a0d923eb83515f311212670f267
F test/spellfix.test f9c1f431e2c096c8775fec032952320c0e4700db
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
@@ -1228,10 +1319,13 @@ F test/subselect.test 0966aa8e720224dbd6a5e769a3ec2a723e332303
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
+F test/swarmvtab.test c2279311b44de032f86a8295a9b06818d864856f9428b4c99eee91a0d419cf25
+F test/swarmvtab2.test 9a3a68a1e58d00f4ed6c68d12d52f2df971b9e22a80a41f6f8c1409abba8e5b4
+F test/swarmvtabfault.test 00aec54665909490f5c383f3cae3b5d18bd97c12490b429ff8752a3027acfa42
F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
F test/sync.test 2f84bdbc2b2df1fcb0220575b4b9f8cea94b7529
F test/sync2.test 6be8ed007fa063b147773c1982b5bdba97a32badc536bdc6077eff5cf8710ece
-F test/syscall.test 7a60601770172a8014a4d222d5f3d95a5d2b5c47fbb0374e2698e89c99e37256
+F test/syscall.test a39d9a36f852ae6e4800f861bc2f2e83f68bbc2112d9399931ecfadeabd2d69d
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
F test/tabfunc01.test c47171c36b3d411df2bd49719dcaa5d034f8d277477fd41d253940723b969a51
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
@@ -1245,7 +1339,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
-F test/tester.tcl 581f0185434daf7026ccede4c07e8d1479186ec5
+F test/tester.tcl 9948bd856ce8a1c127f2f7900365387a42a917ce0dc87185bdd128fa5b11aff2
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1432,8 +1526,13 @@ F test/tt3_vacuum.c 1753f45917699c9c1f66b64c717a717c9379f776
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
+<<<<<<< HEAD
F test/unionvtab.test 3cb7463d8c6a34ae7c043e53103d63d19465a1488f4587a981ae05e978cc6d26
F test/unionvtabfault.test ccb87c510efd0da88d90d813cfaeebe69f2be78cdfbdc3343b04fd9fc507d887
+=======
+F test/unionvtab.test 595fb601de00188ca5e7c6dbe266c17a0faf234cf434ce85eccec1a929ef9baf
+F test/unionvtabfault.test 26b6854d5aef9005cd630513025690bff1b7378ae9c97b81e2a3cbe84eee0f58
+>>>>>>> 8a87f7e... sqlite: Upgrade from 3.20.1 to 3.21.0.
F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2
F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
@@ -1454,7 +1553,7 @@ F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
F test/view.test 765802c7a66d37fabd5ac8e2f2dbe572b43eb9ab
F test/vtab1.test 8f91b9538d1404c3932293a588c4344218a0c94792d4289bb55e41020e7b3fff
-F test/vtab2.test f8cd1bb9aba7143eba97812d9617880a36d247ad
+F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c84082
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3
F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391
@@ -1466,15 +1565,16 @@ F test/vtabA.test 1317f06a03597eee29f40a49b6c21e1aaba4285f
F test/vtabB.test 04df5dc531b9f44d9ca65b9c1b79f12b5922a796
F test/vtabC.test 4528f459a13136f982e75614d120aef165f17292
F test/vtabD.test 05b3f1d77117271671089e48719524b676842e96
-F test/vtabE.test d5024aa42754962f6bb0afd261681686488e7afe
+F test/vtabE.test 2a143fe75a11275781d1fd1988d86b66a3f69cb98f4add62e3da8fd0f637b45f
F test/vtabF.test 1918844c7c902f6a16c8dacf1ec8f84886d6e78b
-F test/vtabH.test 26d54e8b5407f797638b787a55f9c88323850a58dd142de02d06b9a1159bd283
+F test/vtabH.test 3cf9aa1c1c4381b3b3ac33f933376f06fbb99d2294a83c79b7562d3ed87be450
F test/vtabI.test 751b07636700dbdea328e4265b6077ccd6811a3f
+F test/vtabJ.test d7b73675708cf63cfcb9d443bb451fc01a028347275b7311e51f9fdf3ca6757f
F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c3784c6783
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
F test/wal.test 613efec03e517e1775d86b993a54877d2e29a477
-F test/wal2.test 56b0bc95b8693a0be294f8d210c49025dd094bd7
+F test/wal2.test 6ac39b94a284ebac6efb6be93b0cdfe73ee6083f129555e3144d8a615e9900ef
F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
F test/wal5.test 9c11da7aeccd83a46d79a556ad11a18d3cb15aa9
@@ -1512,12 +1612,12 @@ F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
F test/where7.test f520bcec2c3d12dc4615623b06b2aec7c2d67e94
F test/where8.test 98eedca0d375fb400b8377269c4b4686582dfb45
F test/where9.test 729c3ba9b47e8f9f1aab96bae7dad2a524f1d1a2
-F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
+F test/whereA.test 6c6a420ca7d313242f9b1bd471dc80e4d0f8323700ba9c78df0bb843d4daa3b4
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
F test/whereD.test 711d4df58d6d4fb9b3f5ce040b818564198be002
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
-F test/whereF.test 97a86ecdfa4c21684fdff501dbd2cb7397689be8676d0dbad1f5a0892c6b56a3
+F test/whereF.test d44b58338fe5ddd7286023e9bedb255aa264a6c4d2168b49591b167371c675c7
F test/whereG.test dde4c52a97385a55be6a7cd46be8373f0cf35501
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/whereI.test eab5b226bbc344ac70d7dc09b963a064860ae6d7
@@ -1526,7 +1626,7 @@ F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
-F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
+F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2aeee74
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
@@ -1540,13 +1640,14 @@ F test/without_rowid3.test 2724c787a51a5dce09d078453a758117b4b728f1
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
F test/without_rowid5.test 89b1c587bd92a0590e440da33e7666bf4891572a
F test/without_rowid6.test 1f99644e6508447fb050f73697350c7ceca3392e
-F test/wordcount.c 06efb84b7c48a4973c2c24ea06c93d00bce24389
+F test/wordcount.c cb589cec469a1d90add05b1f8cee75c7210338d87a5afd65260ed5c0f4bbf8ac
+F test/writecrash.test f1da7f7adfe8d7f09ea79b42e5ca6dcc41102f27f8e334ad71539501ddd910cc
F test/zeroblob.test 3857870fe681b8185654414a9bccfde80b62a0fa
F test/zerodamage.test e59a56443d6298ecf7435f618f0b27654f0c849e
F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
F tool/GetTclKit.bat 6afa640edc7810725aec61c3076ac617c4aaf0b7
F tool/Replace.cs 02c67258801c2fb5f63231e0ac0f220b4b36ba91
-F tool/addopcodes.tcl edbd53806bf20e25af2373ad0c091be4385081c1aa1813b916bf093f94ed8380
+F tool/addopcodes.tcl 7181c041d495e3f26acc36d15c86923ed722285f9015f017f41a3efdb9a0dab4
F tool/build-all-msvc.bat c12328d06c45fec8baada5949e3d5af54bf8c887 x
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
F tool/cg_anno.tcl f95b0006c52cf7f0496b506343415b6ee3cdcdd3 x
@@ -1560,25 +1661,27 @@ F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
-F tool/lemon.c 5a04dff28578a67415cea5bf981b893c50cebfdd4388fb21254d1892525edfd8
-F tool/lempar.c 10579a61dc2290182725e7abdefe311dd8b521a8f7f0aabbfc571e9012a09eaf
+F tool/lemon.c e6056373044d55296d21f81467dba7632bbb81dc49af072b3f0e76338771497e
+F tool/lempar.c 105d0d9cbe5a25d24d4769241ffbfc63ac7c09e6ccee0dc43dcc8a4c4ae4e426
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
-F tool/mkautoconfamal.sh e855df211ecbcc7131dee817110ff386cfb112f7
+F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e
+F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
F tool/mkkeywordhash.c 2e852ac0dfdc5af18886dc1ce7e9676d11714ae3df0a282dc7d90b3a0fe2033c
F tool/mkmsvcmin.tcl cbd93f1cfa3a0a9ae56fc958510aa3fc3ac65e29cb111716199e3d0e66eefaa4
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
-F tool/mkopcodeh.tcl bb04ab6e5e2000c91e0c69a597e7e36e002320d123e2e1944cb2819181b72ee9
+F tool/mkopcodeh.tcl 4ee2a30ccbd900dc4d5cdb61bdab87cd2166cd2affcc78c9cc0b8d22a65b2eee
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkpragmatab.tcl 2144bc8550a6471a029db262a132d2df4b9e0db61b90398bf64f5b7b3f8d92cd
-F tool/mkshellc.tcl 69c38ecd7b74b2b0799a35ce20e1e3998e504d8c99c100ca4b98ae9d8f6279bc
+F tool/mkshellc.tcl 574307265b49d813301fba91ccd74e6a26d33f65f74b6891c320a0ffbee07895
+F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl fef88397668ae83166735c41af99d79f56afaabb
-F tool/mksqlite3c.tcl f6214285bec900d28441366ca31af327aade18bbc424b0480497966ec05bc43c
-F tool/mksqlite3h.tcl 51bd5e7e840a920388a5966c9f2ccc618f434c57bd68c1bab4085b2553e1e237
+F tool/mksqlite3c.tcl 1fb69d39166f52d802a70ec37d99bca51d011c8ab30be27bc495be493196ae41
+F tool/mksqlite3h.tcl f92f994d9709aeb9e2b6e6f9fc8b069d2f55202c8e23f453edc44390a25982dc
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091
@@ -1596,23 +1699,23 @@ F tool/showstat4.c 0682ebea7abf4d3657f53c4a243f2e7eab48eab344ed36a94bb75dcd19a5c
F tool/showwal.c ad9d768f96ca6199ad3a8c9562d679680bd032dd01204ea3e5ea6fb931d81847
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
F tool/spaceanal.tcl f40dc82b4d5e39d040a02a3ec38268e324068815e4292a15ffa30ee93208bbfd
-F tool/speed-check.sh fd24151fd66465f01886c3f75faf8fa46d19f068c69d16514ca73887adcdafe4
+F tool/speed-check.sh a97ae367e9172a706101901e7caef48f1a14fc8a49053b25e79f6a67296b3412
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
F tool/speedtest16.c ecb6542862151c3e6509bbc00509b234562ae81e
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
-F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
+F tool/split-sqlite3c.tcl 3efcd4240b738f6bb2b5af0aea7e1e0ef9bc1c61654f645076cec883030b710c
F tool/sqldiff.c 30879bbc8de686df4624e86adce2d8981f500904c1cfb55b5d1eea2ffd9341eb
+F tool/sqlite3_analyzer.c.in 771d15fb9c67645fd8ef932a438f98959da4b7c7da3cb87ae1850b27c969edf3
F tool/srcck1.c 371de5363b70154012955544f86fdee8f6e5326f
F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43
F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
F tool/symbols.sh c5a617b8c61a0926747a56c65f5671ef8ac0e148
-F tool/tostr.tcl 96022f35ada2194f6f8ccf6fd95809e90ed277c4
F tool/varint.c 5d94cb5003db9dbbcbcc5df08d66f16071aee003
F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c
F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
-F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
+F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 8a4acea31e0f9c562949a2d767329533c0930d699ea19c6704c0ca0aa9154068
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F vsixtest/App.xaml b76d3b48860e7454775c47ea38ffea9c4abe3e85
@@ -1636,6 +1739,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
+<<<<<<< HEAD
P d14fc621e918915bbf8e04597eb238ea78dff3d9c5eb4402cb88692d00dbdfee
R 71a176dbaf167be1fc010ab41b45c196
T *branch * index-on-date-func
@@ -1643,4 +1747,13 @@ T *sym-index-on-date-func *
T -sym-trunk *
U drh
Z 6174c3091e77280f162146b58b68a8ad
+=======
+P 41ef34a1f0650c50cacb203665cd9d57db53a49c979bf0d5a78937517f763a2c
+R ba55e91a353da744095752f95418b3a4
+T +bgcolor * #d0c0ff
+T +sym-release *
+T +sym-version-3.21.0 *
+U drh
+Z c165baaf48a254c276ef91f282f216a1
+>>>>>>> 8a87f7e... sqlite: Upgrade from 3.20.1 to 3.21.0.
# Remove this line to create a well-formed manifest.
diff --git a/third_party/sqlite/src/manifest.uuid b/third_party/sqlite/src/manifest.uuid
index 473e071..8a16768 100644
--- a/third_party/sqlite/src/manifest.uuid
+++ b/third_party/sqlite/src/manifest.uuid
@@ -1 +1 @@
-0a5e1c04d9d07bb7fd6546a9ddac1bf42b19ea19c2b79570aea6cd4226887a27
+1a584e499906b5c87ec7d43d4abce641fdf017c42125b083109bc77c4de48827
diff --git a/third_party/sqlite/src/src/alter.c b/third_party/sqlite/src/src/alter.c
index 69397e1..93ac16d 100644
--- a/third_party/sqlite/src/src/alter.c
+++ b/third_party/sqlite/src/src/alter.c
@@ -403,9 +403,9 @@ void sqlite3AlterRenameTable(
char *zWhere = 0; /* Where clause to locate temp triggers */
#endif
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
- int savedDbFlags; /* Saved value of db->flags */
+ u32 savedDbFlags; /* Saved value of db->mDbFlags */
- savedDbFlags = db->flags;
+ savedDbFlags = db->mDbFlags;
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
assert( pSrc->nSrc==1 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
@@ -414,7 +414,7 @@ void sqlite3AlterRenameTable(
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zDbSName;
- db->flags |= SQLITE_PreferBuiltin;
+ db->mDbFlags |= DBFLAG_PreferBuiltin;
/* Get a NULL terminated version of the new table name. */
zName = sqlite3NameFromToken(db, pName);
@@ -579,7 +579,7 @@ void sqlite3AlterRenameTable(
exit_rename_table:
sqlite3SrcListDelete(db, pSrc);
sqlite3DbFree(db, zName);
- db->flags = savedDbFlags;
+ db->mDbFlags = savedDbFlags;
}
/*
@@ -680,11 +680,11 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
if( zCol ){
char *zEnd = &zCol[pColDef->n-1];
- int savedDbFlags = db->flags;
+ u32 savedDbFlags = db->mDbFlags;
while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
*zEnd-- = '\0';
}
- db->flags |= SQLITE_PreferBuiltin;
+ db->mDbFlags |= DBFLAG_PreferBuiltin;
sqlite3NestedParse(pParse,
"UPDATE \"%w\".%s SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
@@ -693,7 +693,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
zTab
);
sqlite3DbFree(db, zCol);
- db->flags = savedDbFlags;
+ db->mDbFlags = savedDbFlags;
}
/* Make sure the schema version is at least 3. But do not upgrade
diff --git a/third_party/sqlite/src/src/attach.c b/third_party/sqlite/src/src/attach.c
index 2e8f8c1..fbbd37b 100644
--- a/third_party/sqlite/src/src/attach.c
+++ b/third_party/sqlite/src/src/attach.c
@@ -93,10 +93,6 @@ static void attachFunc(
);
goto attach_error;
}
- if( !db->autoCommit ){
- zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction");
- goto attach_error;
- }
for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zDbSName;
assert( z && zName );
@@ -288,11 +284,6 @@ static void detachFunc(
sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
goto detach_error;
}
- if( !db->autoCommit ){
- sqlite3_snprintf(sizeof(zErr), zErr,
- "cannot DETACH database within transaction");
- goto detach_error;
- }
if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){
sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
goto detach_error;
diff --git a/third_party/sqlite/src/src/auth.c b/third_party/sqlite/src/src/auth.c
index 4255440..d85352f 100644
--- a/third_party/sqlite/src/src/auth.c
+++ b/third_party/sqlite/src/src/auth.c
@@ -118,11 +118,9 @@ int sqlite3AuthReadCol(
#endif
);
if( rc==SQLITE_DENY ){
- if( db->nDb>2 || iDb!=0 ){
- sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol);
- }else{
- sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol);
- }
+ char *z = sqlite3_mprintf("%s.%s", zTab, zCol);
+ if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z);
+ sqlite3ErrorMsg(pParse, "access to %z is prohibited", z);
pParse->rc = SQLITE_AUTH;
}else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){
sqliteAuthBadReturnCode(pParse);
diff --git a/third_party/sqlite/src/src/btree.c b/third_party/sqlite/src/src/btree.c
index 26c2d76..e349eac 100644
--- a/third_party/sqlite/src/src/btree.c
+++ b/third_party/sqlite/src/src/btree.c
@@ -439,7 +439,9 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){
#endif /* SQLITE_OMIT_SHARED_CACHE */
-static void releasePage(MemPage *pPage); /* Forward reference */
+static void releasePage(MemPage *pPage); /* Forward reference */
+static void releasePageOne(MemPage *pPage); /* Forward reference */
+static void releasePageNotNull(MemPage *pPage); /* Forward reference */
/*
***** This routine is used inside of assert() only ****
@@ -598,11 +600,13 @@ static void btreeClearHasContent(BtShared *pBt){
*/
static void btreeReleaseAllCursorPages(BtCursor *pCur){
int i;
- for(i=0; i<=pCur->iPage; i++){
- releasePage(pCur->apPage[i]);
- pCur->apPage[i] = 0;
+ if( pCur->iPage>=0 ){
+ for(i=0; i<pCur->iPage; i++){
+ releasePageNotNull(pCur->apPage[i]);
+ }
+ releasePageNotNull(pCur->pPage);
+ pCur->iPage = -1;
}
- pCur->iPage = -1;
}
/*
@@ -731,7 +735,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(
return rc;
}
}else{
- testcase( p->iPage>0 );
+ testcase( p->iPage>=0 );
btreeReleaseAllCursorPages(p);
}
}
@@ -771,7 +775,7 @@ static int btreeMoveto(
if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
if( pIdxKey->nField==0 ){
- rc = SQLITE_CORRUPT_PGNO(pCur->apPage[pCur->iPage]->pgno);
+ rc = SQLITE_CORRUPT_BKPT;
goto moveto_done;
}
}else{
@@ -836,6 +840,17 @@ int sqlite3BtreeCursorHasMoved(BtCursor *pCur){
}
/*
+** Return a pointer to a fake BtCursor object that will always answer
+** false to the sqlite3BtreeCursorHasMoved() routine above. The fake
+** cursor returned must not be used with any other Btree interface.
+*/
+BtCursor *sqlite3BtreeFakeValidCursor(void){
+ static u8 fakeCursor = CURSOR_VALID;
+ assert( offsetof(BtCursor, eState)==0 );
+ return (BtCursor*)&fakeCursor;
+}
+
+/*
** 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).
@@ -1384,8 +1399,11 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
int sz2 = 0;
int sz = get2byte(&data[iFree+2]);
int top = get2byte(&data[hdr+5]);
+ if( top>=iFree ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
if( iFree2 ){
- if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */
sz2 = get2byte(&data[iFree2+2]);
assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize );
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
@@ -1474,16 +1492,10 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
int pc = get2byte(&aData[iAddr]);
int x;
int usableSize = pPg->pBt->usableSize;
+ int size; /* Size of the free slot */
assert( pc>0 );
- do{
- int size; /* Size of the free slot */
- /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
- ** increasing offset. */
- if( pc>usableSize-4 || pc<iAddr+4 ){
- *pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
- return 0;
- }
+ while( pc<=usableSize-4 ){
/* 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. */
@@ -1491,7 +1503,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
if( (x = size - nByte)>=0 ){
testcase( x==4 );
testcase( x==3 );
- if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){
+ if( size+pc > usableSize ){
*pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
return 0;
}else if( x<4 ){
@@ -1512,7 +1524,11 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
}
iAddr = pc;
pc = get2byte(&aData[pc]);
- }while( pc );
+ if( pc<iAddr+size ) break;
+ }
+ if( pc ){
+ *pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
+ }
return 0;
}
@@ -1626,7 +1642,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
u8 hdr; /* Page header size. 0 or 100 */
u8 nFrag = 0; /* Reduction in fragmentation */
u16 iOrigSize = iSize; /* Original value of iSize */
- u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */
+ u16 x; /* Offset to cell content area */
u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */
unsigned char *data = pPage->aData; /* Page content */
@@ -1636,13 +1652,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( iSize>=4 ); /* Minimum cell size is 4 */
- assert( iStart<=iLast );
-
- /* Overwrite deleted information with zeros when the secure_delete
- ** option is enabled */
- if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
- memset(&data[iStart], 0, iSize);
- }
+ assert( iStart<=pPage->pBt->usableSize-4 );
/* The list of freeblocks must be in ascending order. Find the
** spot on the list where iStart should be inserted.
@@ -1659,7 +1669,9 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}
iPtr = iFreeBlk;
}
- if( iFreeBlk>iLast ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ if( iFreeBlk>pPage->pBt->usableSize-4 ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
assert( iFreeBlk>iPtr || iFreeBlk==0 );
/* At this point:
@@ -1695,19 +1707,25 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
data[hdr+7] -= nFrag;
}
- if( iStart==get2byte(&data[hdr+5]) ){
+ x = get2byte(&data[hdr+5]);
+ 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( iPtr!=hdr+1 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
put2byte(&data[hdr+1], iFreeBlk);
put2byte(&data[hdr+5], iEnd);
}else{
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
- put2byte(&data[iStart], iFreeBlk);
- put2byte(&data[iStart+2], iSize);
}
+ if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
+ /* Overwrite deleted information with zeros when the secure_delete
+ ** option is enabled */
+ memset(&data[iStart], 0, iSize);
+ }
+ put2byte(&data[iStart], iFreeBlk);
+ put2byte(&data[iStart+2], iSize);
pPage->nFree += iOrigSize;
return SQLITE_OK;
}
@@ -2022,7 +2040,7 @@ static Pgno btreePagecount(BtShared *pBt){
}
u32 sqlite3BtreeLastPage(Btree *p){
assert( sqlite3BtreeHoldsMutex(p) );
- assert( ((p->pBt->nPage)&0x8000000)==0 );
+ assert( ((p->pBt->nPage)&0x80000000)==0 );
return btreePagecount(p->pBt);
}
@@ -2049,7 +2067,7 @@ static int getAndInitPage(
int rc;
DbPage *pDbPage;
assert( sqlite3_mutex_held(pBt->mutex) );
- assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] );
+ assert( pCur==0 || ppPage==&pCur->pPage );
assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
assert( pCur==0 || pCur->iPage>0 );
@@ -2083,7 +2101,10 @@ static int getAndInitPage(
return SQLITE_OK;
getAndInitPage_error:
- if( pCur ) pCur->iPage--;
+ if( pCur ){
+ pCur->iPage--;
+ pCur->pPage = pCur->apPage[pCur->iPage];
+ }
testcase( pgno==0 );
assert( pgno!=0 || rc==SQLITE_CORRUPT );
return rc;
@@ -2092,6 +2113,8 @@ getAndInitPage_error:
/*
** Release a MemPage. This should be called once for each prior
** call to btreeGetPage.
+**
+** Page1 is a special case and must be released using releasePageOne().
*/
static void releasePageNotNull(MemPage *pPage){
assert( pPage->aData );
@@ -2105,6 +2128,16 @@ static void releasePageNotNull(MemPage *pPage){
static void releasePage(MemPage *pPage){
if( pPage ) releasePageNotNull(pPage);
}
+static void releasePageOne(MemPage *pPage){
+ assert( pPage!=0 );
+ assert( pPage->aData );
+ assert( pPage->pBt );
+ assert( pPage->pDbPage!=0 );
+ assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
+ assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ sqlite3PagerUnrefPageOne(pPage->pDbPage);
+}
/*
** Get an unused page.
@@ -2889,7 +2922,8 @@ int sqlite3BtreeGetAutoVacuum(Btree *p){
** set to the value passed to this function as the second parameter,
** set it so.
*/
-#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
+#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS \
+ && !defined(SQLITE_OMIT_WAL)
static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){
sqlite3 *db;
Db *pDb;
@@ -3023,7 +3057,7 @@ static int lockBtree(BtShared *pBt){
}else{
setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1);
if( isOpen==0 ){
- releasePage(pPage1);
+ releasePageOne(pPage1);
return SQLITE_OK;
}
}
@@ -3070,7 +3104,7 @@ static int lockBtree(BtShared *pBt){
** zero and return SQLITE_OK. The caller will call this function
** again with the correct page-size.
*/
- releasePage(pPage1);
+ releasePageOne(pPage1);
pBt->usableSize = usableSize;
pBt->pageSize = pageSize;
freeTempSpace(pBt);
@@ -3124,7 +3158,7 @@ static int lockBtree(BtShared *pBt){
return SQLITE_OK;
page1_init_failed:
- releasePage(pPage1);
+ releasePageOne(pPage1);
pBt->pPage1 = 0;
return rc;
}
@@ -3169,7 +3203,7 @@ static void unlockBtreeIfUnused(BtShared *pBt){
assert( pPage1->aData );
assert( sqlite3PagerRefcount(pBt->pPager)==1 );
pBt->pPage1 = 0;
- releasePageNotNull(pPage1);
+ releasePageOne(pPage1);
}
}
@@ -4035,7 +4069,6 @@ int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){
if( pBtree ){
sqlite3BtreeEnter(pBtree);
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
- int i;
if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
rc = saveCursorPosition(p);
@@ -4049,10 +4082,7 @@ int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){
p->eState = CURSOR_FAULT;
p->skipNext = errCode;
}
- for(i=0; i<=p->iPage; i++){
- releasePage(p->apPage[i]);
- p->apPage[i] = 0;
- }
+ btreeReleaseAllCursorPages(p);
}
sqlite3BtreeLeave(pBtree);
}
@@ -4109,7 +4139,7 @@ int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
testcase( pBt->nPage!=nPage );
pBt->nPage = nPage;
- releasePage(pPage1);
+ releasePageOne(pPage1);
}
assert( countValidCursors(pBt, 1)==0 );
pBt->inTransaction = TRANS_READ;
@@ -4351,10 +4381,8 @@ void sqlite3BtreeCursorZero(BtCursor *p){
int sqlite3BtreeCloseCursor(BtCursor *pCur){
Btree *pBtree = pCur->pBtree;
if( pBtree ){
- int i;
BtShared *pBt = pCur->pBt;
sqlite3BtreeEnter(pBtree);
- sqlite3BtreeClearCursor(pCur);
assert( pBt->pCursor!=0 );
if( pBt->pCursor==pCur ){
pBt->pCursor = pCur->pNext;
@@ -4368,12 +4396,10 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
pPrev = pPrev->pNext;
}while( ALWAYS(pPrev) );
}
- for(i=0; i<=pCur->iPage; i++){
- releasePage(pCur->apPage[i]);
- }
+ btreeReleaseAllCursorPages(pCur);
unlockBtreeIfUnused(pBt);
sqlite3_free(pCur->aOverflow);
- /* sqlite3_free(pCur); */
+ sqlite3_free(pCur->pKey);
sqlite3BtreeLeave(pBtree);
}
return SQLITE_OK;
@@ -4390,9 +4416,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
#ifndef NDEBUG
static void assertCellInfo(BtCursor *pCur){
CellInfo info;
- int iPage = pCur->iPage;
memset(&info, 0, sizeof(info));
- btreeParseCell(pCur->apPage[iPage], pCur->ix, &info);
+ btreeParseCell(pCur->pPage, pCur->ix, &info);
assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 );
}
#else
@@ -4400,9 +4425,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
#endif
static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
if( pCur->info.nSize==0 ){
- int iPage = pCur->iPage;
pCur->curFlags |= BTCF_ValidNKey;
- btreeParseCell(pCur->apPage[iPage],pCur->ix,&pCur->info);
+ btreeParseCell(pCur->pPage,pCur->ix,&pCur->info);
}else{
assertCellInfo(pCur);
}
@@ -4600,7 +4624,7 @@ static int accessPayload(
unsigned char *aPayload;
int rc = SQLITE_OK;
int iIdx = 0;
- MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
+ MemPage *pPage = pCur->pPage; /* Btree page of current entry */
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
#ifdef SQLITE_DIRECT_OVERFLOW_READ
unsigned char * const pBufStart = pBuf; /* Start of original out buffer */
@@ -4796,8 +4820,8 @@ static int accessPayload(
int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
- assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
- assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
+ assert( pCur->iPage>=0 && pCur->pPage );
+ assert( pCur->ix<pCur->pPage->nCell );
return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
}
@@ -4854,18 +4878,23 @@ static const void *fetchPayload(
BtCursor *pCur, /* Cursor pointing to entry to read from */
u32 *pAmt /* Write the number of available bytes here */
){
- u32 amt;
- assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
+ int amt;
+ assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage);
assert( pCur->eState==CURSOR_VALID );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorOwnsBtShared(pCur) );
- assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
+ assert( pCur->ix<pCur->pPage->nCell );
assert( pCur->info.nSize>0 );
- assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
- assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
- amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
- if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal;
- *pAmt = amt;
+ assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB );
+ assert( pCur->info.pPayload<pCur->pPage->aDataEnd ||CORRUPT_DB);
+ amt = pCur->info.nLocal;
+ if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){
+ /* There is too little space on the page for the expected amount
+ ** of local content. Database must be corrupt. */
+ assert( CORRUPT_DB );
+ amt = MAX(0, (int)(pCur->pPage->aDataEnd - pCur->info.pPayload));
+ }
+ *pAmt = (u32)amt;
return (void*)pCur->info.pPayload;
}
@@ -4910,10 +4939,11 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
}
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
- pCur->aiIdx[pCur->iPage++] = pCur->ix;
+ pCur->aiIdx[pCur->iPage] = pCur->ix;
+ pCur->apPage[pCur->iPage] = pCur->pPage;
pCur->ix = 0;
- return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage],
- pCur, pCur->curPagerFlags);
+ pCur->iPage++;
+ return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags);
}
#ifdef SQLITE_DEBUG
@@ -4947,20 +4977,23 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
** the largest cell index.
*/
static void moveToParent(BtCursor *pCur){
+ MemPage *pLeaf;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
- assert( pCur->apPage[pCur->iPage] );
+ assert( pCur->pPage );
assertParentIndex(
pCur->apPage[pCur->iPage-1],
pCur->aiIdx[pCur->iPage-1],
- pCur->apPage[pCur->iPage]->pgno
+ pCur->pPage->pgno
);
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
pCur->ix = pCur->aiIdx[pCur->iPage-1];
- releasePageNotNull(pCur->apPage[pCur->iPage--]);
+ pLeaf = pCur->pPage;
+ pCur->pPage = pCur->apPage[--pCur->iPage];
+ releasePageNotNull(pLeaf);
}
/*
@@ -4972,9 +5005,9 @@ static void moveToParent(BtCursor *pCur){
** 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
-** CURSOR_INVALID. 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.
+** 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
@@ -4992,37 +5025,40 @@ static int moveToRoot(BtCursor *pCur){
assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
- if( pCur->eState>=CURSOR_REQUIRESEEK ){
- if( pCur->eState==CURSOR_FAULT ){
- assert( pCur->skipNext!=SQLITE_OK );
- return pCur->skipNext;
- }
- sqlite3BtreeClearCursor(pCur);
- }
+ assert( pCur->eState < CURSOR_REQUIRESEEK || pCur->iPage<0 );
+ assert( pCur->pgnoRoot>0 || pCur->iPage<0 );
if( pCur->iPage>=0 ){
if( pCur->iPage ){
- do{
- assert( pCur->apPage[pCur->iPage]!=0 );
- releasePageNotNull(pCur->apPage[pCur->iPage--]);
- }while( pCur->iPage);
+ releasePageNotNull(pCur->pPage);
+ while( --pCur->iPage ){
+ releasePageNotNull(pCur->apPage[pCur->iPage]);
+ }
+ pCur->pPage = pCur->apPage[0];
goto skip_init;
}
}else if( pCur->pgnoRoot==0 ){
pCur->eState = CURSOR_INVALID;
- return SQLITE_OK;
+ return SQLITE_EMPTY;
}else{
assert( pCur->iPage==(-1) );
- rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
+ if( pCur->eState>=CURSOR_REQUIRESEEK ){
+ if( pCur->eState==CURSOR_FAULT ){
+ assert( pCur->skipNext!=SQLITE_OK );
+ return pCur->skipNext;
+ }
+ sqlite3BtreeClearCursor(pCur);
+ }
+ rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage,
0, pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
- return rc;
+ return rc;
}
pCur->iPage = 0;
- pCur->curIntKey = pCur->apPage[0]->intKey;
+ pCur->curIntKey = pCur->pPage->intKey;
}
- pRoot = pCur->apPage[0];
+ pRoot = pCur->pPage;
assert( pRoot->pgno==pCur->pgnoRoot );
/* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor
@@ -5037,7 +5073,7 @@ static int moveToRoot(BtCursor *pCur){
** (or the freelist). */
assert( pRoot->intKey==1 || pRoot->intKey==0 );
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
- return SQLITE_CORRUPT_PGNO(pCur->apPage[pCur->iPage]->pgno);
+ return SQLITE_CORRUPT_PGNO(pCur->pPage->pgno);
}
skip_init:
@@ -5045,7 +5081,7 @@ skip_init:
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
- pRoot = pCur->apPage[0];
+ pRoot = pCur->pPage;
if( pRoot->nCell>0 ){
pCur->eState = CURSOR_VALID;
}else if( !pRoot->leaf ){
@@ -5056,6 +5092,7 @@ skip_init:
rc = moveToChild(pCur, subpage);
}else{
pCur->eState = CURSOR_INVALID;
+ rc = SQLITE_EMPTY;
}
return rc;
}
@@ -5074,7 +5111,7 @@ static int moveToLeftmost(BtCursor *pCur){
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
- while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
+ while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
assert( pCur->ix<pPage->nCell );
pgno = get4byte(findCell(pPage, pCur->ix));
rc = moveToChild(pCur, pgno);
@@ -5099,7 +5136,7 @@ static int moveToRightmost(BtCursor *pCur){
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
- while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
+ while( !(pPage = pCur->pPage)->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
pCur->ix = pPage->nCell;
rc = moveToChild(pCur, pgno);
@@ -5122,14 +5159,13 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
- if( pCur->eState==CURSOR_INVALID ){
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
- *pRes = 1;
- }else{
- assert( pCur->apPage[pCur->iPage]->nCell>0 );
- *pRes = 0;
- rc = moveToLeftmost(pCur);
- }
+ assert( pCur->pPage->nCell>0 );
+ *pRes = 0;
+ rc = moveToLeftmost(pCur);
+ }else if( rc==SQLITE_EMPTY ){
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ *pRes = 1;
+ rc = SQLITE_OK;
}
return rc;
}
@@ -5153,28 +5189,26 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
for(ii=0; ii<pCur->iPage; ii++){
assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
}
- assert( pCur->ix==pCur->apPage[pCur->iPage]->nCell-1 );
- assert( pCur->apPage[pCur->iPage]->leaf );
+ assert( pCur->ix==pCur->pPage->nCell-1 );
+ assert( pCur->pPage->leaf );
#endif
return SQLITE_OK;
}
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
- if( CURSOR_INVALID==pCur->eState ){
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
- *pRes = 1;
+ assert( pCur->eState==CURSOR_VALID );
+ *pRes = 0;
+ rc = moveToRightmost(pCur);
+ if( rc==SQLITE_OK ){
+ pCur->curFlags |= BTCF_AtLast;
}else{
- assert( pCur->eState==CURSOR_VALID );
- *pRes = 0;
- rc = moveToRightmost(pCur);
- if( rc==SQLITE_OK ){
- pCur->curFlags |= BTCF_AtLast;
- }else{
- pCur->curFlags &= ~BTCF_AtLast;
- }
-
+ pCur->curFlags &= ~BTCF_AtLast;
}
+ }else if( rc==SQLITE_EMPTY ){
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ *pRes = 1;
+ rc = SQLITE_OK;
}
return rc;
}
@@ -5273,22 +5307,23 @@ int sqlite3BtreeMovetoUnpacked(
rc = moveToRoot(pCur);
if( rc ){
+ if( rc==SQLITE_EMPTY ){
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ *pRes = -1;
+ return SQLITE_OK;
+ }
return rc;
}
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] );
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit );
- assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 );
- if( pCur->eState==CURSOR_INVALID ){
- *pRes = -1;
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
- return SQLITE_OK;
- }
- assert( pCur->apPage[0]->intKey==pCur->curIntKey );
+ assert( pCur->pPage );
+ assert( pCur->pPage->isInit );
+ assert( pCur->eState==CURSOR_VALID );
+ assert( pCur->pPage->nCell > 0 );
+ assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey );
assert( pCur->curIntKey || pIdxKey );
for(;;){
int lwr, upr, idx, c;
Pgno chldPg;
- MemPage *pPage = pCur->apPage[pCur->iPage];
+ 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
@@ -5416,7 +5451,7 @@ int sqlite3BtreeMovetoUnpacked(
*pRes = 0;
rc = SQLITE_OK;
pCur->ix = (u16)idx;
- if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
+ if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT;
goto moveto_finish;
}
if( lwr>upr ) break;
@@ -5427,7 +5462,7 @@ int sqlite3BtreeMovetoUnpacked(
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
assert( pPage->isInit );
if( pPage->leaf ){
- assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
+ assert( pCur->ix<pCur->pPage->nCell );
pCur->ix = (u16)idx;
*pRes = c;
rc = SQLITE_OK;
@@ -5481,9 +5516,10 @@ i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
** opcode, and it that case the cursor will always be valid and
** will always point to a leaf node. */
if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
- if( NEVER(pCur->apPage[pCur->iPage]->leaf==0) ) return -1;
+ if( NEVER(pCur->pPage->leaf==0) ) return -1;
- for(n=1, i=0; i<=pCur->iPage; i++){
+ n = pCur->pPage->nCell;
+ for(i=0; i<pCur->iPage; i++){
n *= pCur->apPage[i]->nCell;
}
return n;
@@ -5536,7 +5572,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
}
}
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
idx = ++pCur->ix;
assert( pPage->isInit );
@@ -5559,7 +5595,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
return SQLITE_DONE;
}
moveToParent(pCur);
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
}while( pCur->ix>=pPage->nCell );
if( pPage->intKey ){
return sqlite3BtreeNext(pCur, 0);
@@ -5582,7 +5618,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int flags){
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur);
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
if( (++pCur->ix)>=pPage->nCell ){
pCur->ix--;
return btreeNext(pCur);
@@ -5641,7 +5677,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
}
}
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
assert( pPage->isInit );
if( !pPage->leaf ){
int idx = pCur->ix;
@@ -5660,7 +5696,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
pCur->ix--;
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
if( pPage->intKey && !pPage->leaf ){
rc = sqlite3BtreePrevious(pCur, 0);
}else{
@@ -5678,7 +5714,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int flags){
pCur->info.nSize = 0;
if( pCur->eState!=CURSOR_VALID
|| pCur->ix==0
- || pCur->apPage[pCur->iPage]->leaf==0
+ || pCur->pPage->leaf==0
){
return btreePrevious(pCur);
}
@@ -6174,7 +6210,7 @@ static int clearCell(
unsigned char *pCell, /* First byte of the Cell */
CellInfo *pInfo /* Size information about the cell */
){
- BtShared *pBt = pPage->pBt;
+ BtShared *pBt;
Pgno ovflPgno;
int rc;
int nOvfl;
@@ -6190,6 +6226,7 @@ static int clearCell(
return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
ovflPgno = get4byte(pCell + pInfo->nSize - 4);
+ pBt = pPage->pBt;
assert( pBt->usableSize > 4 );
ovflPageSize = pBt->usableSize - 4;
nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize;
@@ -6257,21 +6294,20 @@ static int fillInCell(
){
int nPayload;
const u8 *pSrc;
- int nSrc, n, rc;
+ int nSrc, n, rc, mn;
int spaceLeft;
- MemPage *pOvfl = 0;
- MemPage *pToRelease = 0;
+ MemPage *pToRelease;
unsigned char *pPrior;
unsigned char *pPayload;
- BtShared *pBt = pPage->pBt;
- Pgno pgnoOvfl = 0;
+ BtShared *pBt;
+ Pgno pgnoOvfl;
int nHeader;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
/* pPage is not necessarily writeable since pCell might be auxiliary
** buffer space that is separate from the pPage buffer area */
- assert( pCell<pPage->aData || pCell>=&pPage->aData[pBt->pageSize]
+ assert( pCell<pPage->aData || pCell>=&pPage->aData[pPage->pBt->pageSize]
|| sqlite3PagerIswriteable(pPage->pDbPage) );
/* Fill in the header. */
@@ -6291,25 +6327,36 @@ static int fillInCell(
}
/* Fill in the payload */
+ pPayload = &pCell[nHeader];
if( nPayload<=pPage->maxLocal ){
+ /* This is the common case where everything fits on the btree page
+ ** and no overflow pages are required. */
n = nHeader + nPayload;
testcase( n==3 );
testcase( n==4 );
if( n<4 ) n = 4;
*pnSize = n;
- spaceLeft = nPayload;
- pPrior = pCell;
- }else{
- int mn = pPage->minLocal;
- n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4);
- testcase( n==pPage->maxLocal );
- testcase( n==pPage->maxLocal+1 );
- if( n > pPage->maxLocal ) n = mn;
- spaceLeft = n;
- *pnSize = n + nHeader + 4;
- pPrior = &pCell[nHeader+n];
+ assert( nSrc<=nPayload );
+ testcase( nSrc<nPayload );
+ memcpy(pPayload, pSrc, nSrc);
+ memset(pPayload+nSrc, 0, nPayload-nSrc);
+ return SQLITE_OK;
}
- pPayload = &pCell[nHeader];
+
+ /* If we reach this point, it means that some of the content will need
+ ** to spill onto overflow pages.
+ */
+ mn = pPage->minLocal;
+ n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4);
+ testcase( n==pPage->maxLocal );
+ testcase( n==pPage->maxLocal+1 );
+ if( n > pPage->maxLocal ) n = mn;
+ spaceLeft = n;
+ *pnSize = n + nHeader + 4;
+ pPrior = &pCell[nHeader+n];
+ pToRelease = 0;
+ pgnoOvfl = 0;
+ pBt = pPage->pBt;
/* At this point variables should be set as follows:
**
@@ -6335,8 +6382,35 @@ static int fillInCell(
#endif
/* Write the payload into the local Cell and any extra into overflow pages */
- while( nPayload>0 ){
+ while( 1 ){
+ n = nPayload;
+ if( n>spaceLeft ) n = spaceLeft;
+
+ /* If pToRelease is not zero than pPayload points into the data area
+ ** of pToRelease. Make sure pToRelease is still writeable. */
+ assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) );
+
+ /* If pPayload is part of the data area of pPage, then make sure pPage
+ ** is still writeable */
+ assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize]
+ || sqlite3PagerIswriteable(pPage->pDbPage) );
+
+ if( nSrc>=n ){
+ memcpy(pPayload, pSrc, n);
+ }else if( nSrc>0 ){
+ n = nSrc;
+ memcpy(pPayload, pSrc, n);
+ }else{
+ memset(pPayload, 0, n);
+ }
+ nPayload -= n;
+ if( nPayload<=0 ) break;
+ pPayload += n;
+ pSrc += n;
+ nSrc -= n;
+ spaceLeft -= n;
if( spaceLeft==0 ){
+ MemPage *pOvfl = 0;
#ifndef SQLITE_OMIT_AUTOVACUUM
Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */
if( pBt->autoVacuum ){
@@ -6389,30 +6463,6 @@ static int fillInCell(
pPayload = &pOvfl->aData[4];
spaceLeft = pBt->usableSize - 4;
}
- n = nPayload;
- if( n>spaceLeft ) n = spaceLeft;
-
- /* If pToRelease is not zero than pPayload points into the data area
- ** of pToRelease. Make sure pToRelease is still writeable. */
- assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) );
-
- /* If pPayload is part of the data area of pPage, then make sure pPage
- ** is still writeable */
- assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize]
- || sqlite3PagerIswriteable(pPage->pDbPage) );
-
- if( nSrc>0 ){
- if( n>nSrc ) n = nSrc;
- assert( pSrc );
- memcpy(pPayload, pSrc, n);
- }else{
- memset(pPayload, 0, n);
- }
- nPayload -= n;
- pPayload += n;
- pSrc += n;
- nSrc -= n;
- spaceLeft -= n;
}
releasePage(pToRelease);
return SQLITE_OK;
@@ -6444,7 +6494,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
hdr = pPage->hdrOffset;
testcase( pc==get2byte(&data[hdr+5]) );
testcase( pc+sz==pPage->pBt->usableSize );
- if( pc < (u32)get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){
+ if( pc+sz > pPage->pBt->usableSize ){
*pRC = SQLITE_CORRUPT_BKPT;
return;
}
@@ -7311,10 +7361,8 @@ static int balance_nonroot(
+ nMaxCells*sizeof(u16) /* b.szCell */
+ pBt->pageSize; /* aSpace1 */
- /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer
- ** that is more than 6 times the database page size. */
assert( szScratch<=6*(int)pBt->pageSize );
- b.apCell = sqlite3ScratchMalloc( szScratch );
+ b.apCell = sqlite3StackAllocRaw(0, szScratch );
if( b.apCell==0 ){
rc = SQLITE_NOMEM_BKPT;
goto balance_cleanup;
@@ -7892,7 +7940,7 @@ static int balance_nonroot(
** Cleanup before returning.
*/
balance_cleanup:
- sqlite3ScratchFree(b.apCell);
+ sqlite3StackFree(0, b.apCell);
for(i=0; i<nOld; i++){
releasePage(apOld[i]);
}
@@ -7991,7 +8039,7 @@ static int balance(BtCursor *pCur){
do {
int iPage = pCur->iPage;
- MemPage *pPage = pCur->apPage[iPage];
+ MemPage *pPage = pCur->pPage;
if( iPage==0 ){
if( pPage->nOverflow ){
@@ -8007,7 +8055,9 @@ static int balance(BtCursor *pCur){
pCur->iPage = 1;
pCur->ix = 0;
pCur->aiIdx[0] = 0;
- assert( pCur->apPage[1]->nOverflow );
+ pCur->apPage[0] = pPage;
+ pCur->pPage = pCur->apPage[1];
+ assert( pCur->pPage->nOverflow );
}
}else{
break;
@@ -8087,6 +8137,7 @@ static int balance(BtCursor *pCur){
releasePage(pPage);
pCur->iPage--;
assert( pCur->iPage>=0 );
+ pCur->pPage = pCur->apPage[pCur->iPage];
}
}while( rc==SQLITE_OK );
@@ -8218,7 +8269,7 @@ int sqlite3BtreeInsert(
}
assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 );
assert( pPage->leaf || !pPage->intKey );
@@ -8305,10 +8356,10 @@ int sqlite3BtreeInsert(
** 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->apPage[pCur->iPage]->nOverflow = 0;
+ pCur->pPage->nOverflow = 0;
pCur->eState = CURSOR_INVALID;
if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){
- rc = moveToRoot(pCur);
+ btreeReleaseAllCursorPages(pCur);
if( pCur->pKeyInfo ){
assert( pCur->pKey==0 );
pCur->pKey = sqlite3Malloc( pX->nKey );
@@ -8322,7 +8373,7 @@ int sqlite3BtreeInsert(
pCur->nKey = pX->nKey;
}
}
- assert( pCur->apPage[pCur->iPage]->nOverflow==0 );
+ assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 );
end_insert:
return rc;
@@ -8363,13 +8414,13 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
assert( pCur->curFlags & BTCF_WriteFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
- assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
+ assert( pCur->ix<pCur->pPage->nCell );
assert( pCur->eState==CURSOR_VALID );
assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
iCellDepth = pCur->iPage;
iCellIdx = pCur->ix;
- pPage = pCur->apPage[iCellDepth];
+ pPage = pCur->pPage;
pCell = findCell(pPage, iCellIdx);
/* If the bPreserve flag is set to true, then the cursor position must
@@ -8435,11 +8486,16 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** node. The cell from the leaf node needs to be moved to the internal
** node to replace the deleted cell. */
if( !pPage->leaf ){
- MemPage *pLeaf = pCur->apPage[pCur->iPage];
+ MemPage *pLeaf = pCur->pPage;
int nCell;
- Pgno n = pCur->apPage[iCellDepth+1]->pgno;
+ Pgno n;
unsigned char *pTmp;
+ if( iCellDepth<pCur->iPage-1 ){
+ n = pCur->apPage[iCellDepth+1]->pgno;
+ }else{
+ n = pCur->pPage->pgno;
+ }
pCell = findCell(pLeaf, pLeaf->nCell-1);
if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
nCell = pLeaf->xCellSize(pLeaf, pCell);
@@ -8471,16 +8527,19 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** well. */
rc = balance(pCur);
if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){
+ releasePageNotNull(pCur->pPage);
+ pCur->iPage--;
while( pCur->iPage>iCellDepth ){
releasePage(pCur->apPage[pCur->iPage--]);
}
+ pCur->pPage = pCur->apPage[pCur->iPage];
rc = balance(pCur);
}
if( rc==SQLITE_OK ){
if( bSkipnext ){
assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) );
- assert( pPage==pCur->apPage[pCur->iPage] || CORRUPT_DB );
+ assert( pPage==pCur->pPage || CORRUPT_DB );
assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
pCur->eState = CURSOR_SKIPNEXT;
if( iCellIdx>=pPage->nCell ){
@@ -8492,8 +8551,10 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
}else{
rc = moveToRoot(pCur);
if( bPreserve ){
+ btreeReleaseAllCursorPages(pCur);
pCur->eState = CURSOR_REQUIRESEEK;
}
+ if( rc==SQLITE_EMPTY ) rc = SQLITE_OK;
}
}
return rc;
@@ -8958,11 +9019,11 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
i64 nEntry = 0; /* Value to return in *pnEntry */
int rc; /* Return code */
- if( pCur->pgnoRoot==0 ){
+ rc = moveToRoot(pCur);
+ if( rc==SQLITE_EMPTY ){
*pnEntry = 0;
return SQLITE_OK;
}
- rc = moveToRoot(pCur);
/* Unless an error occurs, the following loop runs one iteration for each
** page in the B-Tree structure (not including overflow pages).
@@ -8975,7 +9036,7 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
** this page contains countable entries. Increment the entry counter
** accordingly.
*/
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
if( pPage->leaf || !pPage->intKey ){
nEntry += pPage->nCell;
}
@@ -8998,10 +9059,10 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
return moveToRoot(pCur);
}
moveToParent(pCur);
- }while ( pCur->ix>=pCur->apPage[pCur->iPage]->nCell );
+ }while ( pCur->ix>=pCur->pPage->nCell );
pCur->ix++;
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
}
/* Descend to the child node of the cell that the cursor currently
@@ -9842,7 +9903,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
&& pCsr->pBt->inTransaction==TRANS_WRITE );
assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) );
- assert( pCsr->apPage[pCsr->iPage]->intKey );
+ assert( pCsr->pPage->intKey );
return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
}
diff --git a/third_party/sqlite/src/src/btree.h b/third_party/sqlite/src/src/btree.h
index 7ba2cab..3a0b008 100644
--- a/third_party/sqlite/src/src/btree.h
+++ b/third_party/sqlite/src/src/btree.h
@@ -232,6 +232,7 @@ int sqlite3BtreeCursor(
struct KeyInfo*, /* First argument to compare function */
BtCursor *pCursor /* Space to write cursor structure */
);
+BtCursor *sqlite3BtreeFakeValidCursor(void);
int sqlite3BtreeCursorSize(void);
void sqlite3BtreeCursorZero(BtCursor*);
void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
diff --git a/third_party/sqlite/src/src/btreeInt.h b/third_party/sqlite/src/src/btreeInt.h
index 139a0ab..0694b31a 100644
--- a/third_party/sqlite/src/src/btreeInt.h
+++ b/third_party/sqlite/src/src/btreeInt.h
@@ -500,6 +500,11 @@ struct CellInfo {
** eState==FAULT: Cursor fault with skipNext as error code.
*/
struct BtCursor {
+ u8 eState; /* One of the CURSOR_XXX constants (see below) */
+ u8 curFlags; /* zero or more BTCF_* flags defined below */
+ u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */
+ u8 hints; /* As configured by CursorSetHints() */
+ int nOvflAlloc; /* Allocated size of aOverflow[] array */
Btree *pBtree; /* The Btree to which this cursor belongs */
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext; /* Forms a linked list of all cursors */
@@ -508,13 +513,8 @@ struct BtCursor {
i64 nKey; /* Size of pKey, or last integer key */
void *pKey; /* Saved key that was cursor last known position */
Pgno pgnoRoot; /* The root page of this tree */
- int nOvflAlloc; /* Allocated size of aOverflow[] array */
int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
** Error code if eState==CURSOR_FAULT */
- u8 curFlags; /* zero or more BTCF_* flags defined below */
- u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */
- u8 eState; /* One of the CURSOR_XXX constants (see below) */
- u8 hints; /* As configured by CursorSetHints() */
/* All fields above are zeroed when the cursor is allocated. See
** sqlite3BtreeCursorZero(). Fields that follow must be manually
** initialized. */
@@ -523,7 +523,8 @@ struct BtCursor {
u16 ix; /* Current index for apPage[iPage] */
u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */
struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */
- MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
+ MemPage *pPage; /* Current page */
+ MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */
};
/*
diff --git a/third_party/sqlite/src/src/build.c b/third_party/sqlite/src/src/build.c
index 4fb8fe9..cc4c114 100644
--- a/third_party/sqlite/src/src/build.c
+++ b/third_party/sqlite/src/src/build.c
@@ -479,7 +479,7 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
}
freeIndex(db, pIndex);
}
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
/*
@@ -514,28 +514,26 @@ void sqlite3CollapseDatabaseArray(sqlite3 *db){
/*
** Reset the schema for the database at index iDb. Also reset the
-** TEMP schema.
+** TEMP schema. The reset is deferred if db->nSchemaLock is not zero.
+** Deferred resets may be run by calling with iDb<0.
*/
void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
- Db *pDb;
+ int i;
assert( iDb<db->nDb );
- /* Case 1: Reset the single schema identified by iDb */
- pDb = &db->aDb[iDb];
- assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- assert( pDb->pSchema!=0 );
- sqlite3SchemaClear(pDb->pSchema);
+ if( iDb>=0 ){
+ assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
+ DbSetProperty(db, iDb, DB_ResetWanted);
+ DbSetProperty(db, 1, DB_ResetWanted);
+ }
- /* If any database other than TEMP is reset, then also reset TEMP
- ** since TEMP might be holding triggers that reference tables in the
- ** other database.
- */
- if( iDb!=1 ){
- pDb = &db->aDb[1];
- assert( pDb->pSchema!=0 );
- sqlite3SchemaClear(pDb->pSchema);
+ if( db->nSchemaLock==0 ){
+ for(i=0; i<db->nDb; i++){
+ if( DbHasProperty(db, i, DB_ResetWanted) ){
+ sqlite3SchemaClear(db->aDb[i].pSchema);
+ }
+ }
}
- return;
}
/*
@@ -545,13 +543,14 @@ void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
int i;
sqlite3BtreeEnterAll(db);
+ assert( db->nSchemaLock==0 );
for(i=0; i<db->nDb; i++){
Db *pDb = &db->aDb[i];
if( pDb->pSchema ){
sqlite3SchemaClear(pDb->pSchema);
}
}
- db->flags &= ~SQLITE_InternChanges;
+ db->mDbFlags &= ~DBFLAG_SchemaChange;
sqlite3VtabUnlockList(db);
sqlite3BtreeLeaveAll(db);
sqlite3CollapseDatabaseArray(db);
@@ -561,7 +560,7 @@ void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
** This routine is called when a commit occurs.
*/
void sqlite3CommitInternalChanges(sqlite3 *db){
- db->flags &= ~SQLITE_InternChanges;
+ db->mDbFlags &= ~DBFLAG_SchemaChange;
}
/*
@@ -599,13 +598,16 @@ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
*/
static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
Index *pIndex, *pNext;
- TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */
+#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. */
- TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ?
- db->lookaside.nOut : 0 );
+ int nLookaside = 0;
+ if( db && (pTable->tabFlags & TF_Ephemeral)==0 ){
+ nLookaside = sqlite3LookasideUsed(db, 0);
+ }
+#endif
/* Delete all indices associated with this table. */
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
@@ -639,7 +641,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
sqlite3DbFree(db, pTable);
/* Verify that no lookaside memory was used by schema tables */
- assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
+ assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) );
}
void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Do not delete the table until the reference count reaches zero. */
@@ -665,7 +667,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
pDb = &db->aDb[iDb];
p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
sqlite3DeleteTable(db, p);
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
/*
@@ -778,7 +780,8 @@ int sqlite3TwoPartName(
return -1;
}
}else{
- assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0);
+ assert( db->init.iDb==0 || db->init.busy
+ || (db->mDbFlags & DBFLAG_Vacuum)!=0);
iDb = db->init.iDb;
*pUnqual = pName1;
}
@@ -1010,7 +1013,8 @@ void sqlite3StartTable(
}else
#endif
{
- pParse->addrCrTab = sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
+ pParse->addrCrTab =
+ sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
}
sqlite3OpenMasterTable(pParse, iDb);
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
@@ -1059,12 +1063,10 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
Column *pCol;
sqlite3 *db = pParse->db;
if( (p = pParse->pNewTable)==0 ) return;
-#if SQLITE_MAX_COLUMN
if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName);
return;
}
-#endif
z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
if( z==0 ) return;
memcpy(z, pName->z, pName->n);
@@ -1670,9 +1672,8 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
** Changes include:
**
** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
-** (2) Convert the OP_CreateTable into an OP_CreateIndex. There is
-** no rowid btree for a WITHOUT ROWID. Instead, the canonical
-** data storage is a covering index btree.
+** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY
+** into BTREE_BLOBKEY.
** (3) Bypass the creation of the sqlite_master table entry
** for the PRIMARY KEY as the primary key index is now
** identified by the sqlite_master table entry of the table itself.
@@ -1680,7 +1681,7 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
** schema to the rootpage from the main table.
** (5) Add all table columns to the PRIMARY KEY Index object
** so that the PRIMARY KEY is a covering index. The surplus
-** columns are part of KeyInfo.nXField and are not used for
+** columns are part of KeyInfo.nAllField and are not used for
** sorting or lookup or uniqueness checks.
** (6) Replace the rowid tail on all automatically generated UNIQUE
** indices with the PRIMARY KEY columns.
@@ -1709,13 +1710,12 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
** virtual tables */
if( IN_DECLARE_VTAB ) return;
- /* Convert the OP_CreateTable opcode that would normally create the
- ** root-page for the table into an OP_CreateIndex opcode. The index
- ** created will become the PRIMARY KEY index.
+ /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
+ ** into BTREE_BLOBKEY.
*/
if( pParse->addrCrTab ){
assert( v );
- sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex);
+ sqlite3VdbeChangeP3(v, pParse->addrCrTab, BTREE_BLOBKEY);
}
/* Locate the PRIMARY KEY index. Or, if this table was originally
@@ -2055,7 +2055,7 @@ void sqlite3EndTable(
return;
}
pParse->pNewTable = 0;
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
#ifndef SQLITE_OMIT_ALTERTABLE
if( !p->pSelect ){
@@ -2154,6 +2154,9 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
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;
+#endif
#ifndef SQLITE_OMIT_AUTHORIZATION
sqlite3_xauth xAuth; /* Saved xAuth pointer */
#endif
@@ -2161,8 +2164,11 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable );
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( sqlite3VtabCallConnect(pParse, pTable) ){
- return SQLITE_ERROR;
+ db->nSchemaLock++;
+ rc = sqlite3VtabCallConnect(pParse, pTable);
+ db->nSchemaLock--;
+ if( rc ){
+ return 1;
}
if( IsVirtual(pTable) ) return 0;
#endif
@@ -2358,14 +2364,6 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
** is also added (this can happen with an auto-vacuum database).
*/
static void destroyTable(Parse *pParse, Table *pTab){
-#ifdef SQLITE_OMIT_AUTOVACUUM
- Index *pIdx;
- int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
- destroyRootPage(pParse, pTab->tnum, iDb);
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- destroyRootPage(pParse, pIdx->tnum, iDb);
- }
-#else
/* 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
@@ -2408,7 +2406,6 @@ static void destroyTable(Parse *pParse, Table *pTab){
iDestroyed = iLargest;
}
}
-#endif
}
/*
@@ -2835,7 +2832,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
addr2 = sqlite3VdbeCurrentAddr(v);
}
sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
- sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
+ sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
sqlite3ReleaseTempReg(pParse, regRecord);
@@ -3324,7 +3321,7 @@ void sqlite3CreateIndex(
sqlite3OomFault(db);
goto exit_create_index;
}
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
if( pTblName!=0 ){
pIndex->tnum = db->init.newTnum;
}
@@ -3360,7 +3357,7 @@ void sqlite3CreateIndex(
** 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);
- sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem);
+ sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
/* Gather the complete text of the CREATE INDEX statement into
** the zStmt variable
@@ -3882,8 +3879,10 @@ SrcList *sqlite3SrcListAppendFromTerm(
*/
void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
assert( pIndexedBy!=0 );
- if( p && ALWAYS(p->nSrc>0) ){
- struct SrcList_item *pItem = &p->a[p->nSrc-1];
+ if( p && pIndexedBy->n>0 ){
+ struct SrcList_item *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 );
@@ -3893,7 +3892,7 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
pItem->fg.notIndexed = 1;
}else{
pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
- pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0);
+ pItem->fg.isIndexedBy = 1;
}
}
}
diff --git a/third_party/sqlite/src/src/callback.c b/third_party/sqlite/src/src/callback.c
index eb2e31b..38ba172 100644
--- a/third_party/sqlite/src/src/callback.c
+++ b/third_party/sqlite/src/src/callback.c
@@ -374,7 +374,7 @@ FuncDef *sqlite3FindFunction(
/* If no match is found, search the built-in functions.
**
- ** If the SQLITE_PreferBuiltin flag is set, then search the built-in
+ ** If the DBFLAG_PreferBuiltin flag is set, then search the built-in
** functions even if a prior app-defined function was found. And give
** priority to built-in functions.
**
@@ -384,7 +384,7 @@ FuncDef *sqlite3FindFunction(
** 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->flags & SQLITE_PreferBuiltin)!=0) ){
+ if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){
bestScore = 0;
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
p = functionSearch(h, zName);
@@ -457,8 +457,8 @@ void sqlite3SchemaClear(void *p){
pSchema->pSeqTab = 0;
if( pSchema->schemaFlags & DB_SchemaLoaded ){
pSchema->iGeneration++;
- pSchema->schemaFlags &= ~DB_SchemaLoaded;
}
+ pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted);
}
/*
diff --git a/third_party/sqlite/src/src/ctime.c b/third_party/sqlite/src/src/ctime.c
index 059bb84..9430924 100644
--- a/third_party/sqlite/src/src/ctime.c
+++ b/third_party/sqlite/src/src/ctime.c
@@ -184,6 +184,9 @@ static const char * const sqlite3azCompileOpt[] = {
#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",
#endif
diff --git a/third_party/sqlite/src/src/dbpage.c b/third_party/sqlite/src/src/dbpage.c
new file mode 100644
index 0000000..9cd112a
--- /dev/null
+++ b/third_party/sqlite/src/src/dbpage.c
@@ -0,0 +1,329 @@
+/*
+** 2017-10-11
+**
+** 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 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
+** uncommitted changes and changes recorded in the WAL file are correctly
+** retrieved.
+**
+** Usage example:
+**
+** SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
+**
+** This is an eponymous virtual table so it does not need to be created before
+** use. The optional argument to the sqlite_dbpage() table name is the
+** schema for the database file that is to be read. The default schema is
+** "main".
+**
+** The data field of sqlite_dbpage table can be updated. The new
+** value must be a BLOB which is the correct page size, otherwise the
+** update fails. Rows may not be deleted or inserted.
+*/
+
+#include "sqliteInt.h" /* Requires access to internal data structures */
+#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
+ && !defined(SQLITE_OMIT_VIRTUALTABLE)
+
+typedef struct DbpageTable DbpageTable;
+typedef struct DbpageCursor DbpageCursor;
+
+struct DbpageCursor {
+ sqlite3_vtab_cursor base; /* Base class. Must be first */
+ int pgno; /* Current page number */
+ int mxPgno; /* Last page to visit on this scan */
+};
+
+struct DbpageTable {
+ sqlite3_vtab base; /* Base class. Must be first */
+ sqlite3 *db; /* The database */
+ Pager *pPager; /* Pager being read/written */
+ int iDb; /* Index of database to analyze */
+ int szPage; /* Size of each page in bytes */
+ int nPage; /* Number of pages in the file */
+};
+
+/*
+** Connect to or create a dbpagevfs virtual table.
+*/
+static int dbpageConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ DbpageTable *pTab = 0;
+ int rc = SQLITE_OK;
+ int iDb;
+
+ if( argc>=4 ){
+ Token nm;
+ sqlite3TokenInit(&nm, (char*)argv[3]);
+ iDb = sqlite3FindDb(db, &nm);
+ if( iDb<0 ){
+ *pzErr = sqlite3_mprintf("no such schema: %s", argv[3]);
+ return SQLITE_ERROR;
+ }
+ }else{
+ iDb = 0;
+ }
+ 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));
+ if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
+ }
+
+ assert( rc==SQLITE_OK || pTab==0 );
+ if( rc==SQLITE_OK ){
+ Btree *pBt = db->aDb[iDb].pBt;
+ memset(pTab, 0, sizeof(DbpageTable));
+ pTab->db = db;
+ pTab->iDb = iDb;
+ pTab->pPager = pBt ? sqlite3BtreePager(pBt) : 0;
+ }
+
+ *ppVtab = (sqlite3_vtab*)pTab;
+ return rc;
+}
+
+/*
+** Disconnect from or destroy a dbpagevfs virtual table.
+*/
+static int dbpageDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** idxNum:
+**
+** 0 full table scan
+** 1 pgno=?1
+*/
+static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+ int i;
+ pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
+ if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ pIdxInfo->estimatedRows = 1;
+ pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
+ pIdxInfo->estimatedCost = 1.0;
+ pIdxInfo->idxNum = 1;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ break;
+ }
+ }
+ if( pIdxInfo->nOrderBy>=1
+ && pIdxInfo->aOrderBy[0].iColumn<=0
+ && pIdxInfo->aOrderBy[0].desc==0
+ ){
+ pIdxInfo->orderByConsumed = 1;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Open a new dbpagevfs cursor.
+*/
+static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ DbpageCursor *pCsr;
+
+ pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
+ if( pCsr==0 ){
+ return SQLITE_NOMEM_BKPT;
+ }else{
+ memset(pCsr, 0, sizeof(DbpageCursor));
+ pCsr->base.pVtab = pVTab;
+ pCsr->pgno = -1;
+ }
+
+ *ppCursor = (sqlite3_vtab_cursor *)pCsr;
+ return SQLITE_OK;
+}
+
+/*
+** Close a dbpagevfs cursor.
+*/
+static int dbpageClose(sqlite3_vtab_cursor *pCursor){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/*
+** Move a dbpagevfs cursor to the next entry in the file.
+*/
+static int dbpageNext(sqlite3_vtab_cursor *pCursor){
+ int rc = SQLITE_OK;
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ pCsr->pgno++;
+ return rc;
+}
+
+static int dbpageEof(sqlite3_vtab_cursor *pCursor){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ return pCsr->pgno > pCsr->mxPgno;
+}
+
+static int dbpageFilter(
+ sqlite3_vtab_cursor *pCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
+ int rc = SQLITE_OK;
+ Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
+
+ pTab->szPage = sqlite3BtreeGetPageSize(pBt);
+ pTab->nPage = sqlite3BtreeLastPage(pBt);
+ if( idxNum==1 ){
+ pCsr->pgno = sqlite3_value_int(argv[0]);
+ if( pCsr->pgno<1 || pCsr->pgno>pTab->nPage ){
+ pCsr->pgno = 1;
+ pCsr->mxPgno = 0;
+ }else{
+ pCsr->mxPgno = pCsr->pgno;
+ }
+ }else{
+ pCsr->pgno = 1;
+ pCsr->mxPgno = pTab->nPage;
+ }
+ return rc;
+}
+
+static int dbpageColumn(
+ sqlite3_vtab_cursor *pCursor,
+ sqlite3_context *ctx,
+ int i
+){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
+ int rc = SQLITE_OK;
+ switch( i ){
+ case 0: { /* pgno */
+ sqlite3_result_int(ctx, pCsr->pgno);
+ break;
+ }
+ case 1: { /* data */
+ DbPage *pDbPage = 0;
+ rc = sqlite3PagerGet(pTab->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pTab->szPage,
+ SQLITE_TRANSIENT);
+ }
+ sqlite3PagerUnref(pDbPage);
+ break;
+ }
+ default: { /* schema */
+ sqlite3 *db = sqlite3_context_db_handle(ctx);
+ sqlite3_result_text(ctx, db->aDb[pTab->iDb].zDbSName, -1, SQLITE_STATIC);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ *pRowid = pCsr->pgno;
+ return SQLITE_OK;
+}
+
+static int dbpageUpdate(
+ sqlite3_vtab *pVtab,
+ int argc,
+ sqlite3_value **argv,
+ sqlite_int64 *pRowid
+){
+ DbpageTable *pTab = (DbpageTable *)pVtab;
+ int pgno;
+ DbPage *pDbPage = 0;
+ int rc = SQLITE_OK;
+ char *zErr = 0;
+
+ if( argc==1 ){
+ zErr = "cannot delete";
+ goto update_fail;
+ }
+ pgno = sqlite3_value_int(argv[0]);
+ if( pgno<1 || pgno>pTab->nPage ){
+ zErr = "bad page number";
+ goto update_fail;
+ }
+ if( sqlite3_value_int(argv[1])!=pgno ){
+ zErr = "cannot insert";
+ goto update_fail;
+ }
+ if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
+ || sqlite3_value_bytes(argv[3])!=pTab->szPage
+ ){
+ zErr = "bad page value";
+ goto update_fail;
+ }
+ rc = sqlite3PagerGet(pTab->pPager, pgno, (DbPage**)&pDbPage, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerWrite(pDbPage);
+ if( rc==SQLITE_OK ){
+ memcpy(sqlite3PagerGetData(pDbPage),
+ sqlite3_value_blob(argv[3]),
+ pTab->szPage);
+ }
+ }
+ sqlite3PagerUnref(pDbPage);
+ return rc;
+
+update_fail:
+ sqlite3_free(pVtab->zErrMsg);
+ pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
+ return SQLITE_ERROR;
+}
+
+/*
+** Invoke this routine to register the "dbpage" virtual table module
+*/
+int sqlite3DbpageRegister(sqlite3 *db){
+ static sqlite3_module dbpage_module = {
+ 0, /* iVersion */
+ dbpageConnect, /* xCreate */
+ dbpageConnect, /* xConnect */
+ dbpageBestIndex, /* xBestIndex */
+ dbpageDisconnect, /* xDisconnect */
+ dbpageDisconnect, /* xDestroy */
+ dbpageOpen, /* xOpen - open a cursor */
+ dbpageClose, /* xClose - close a cursor */
+ dbpageFilter, /* xFilter - configure scan constraints */
+ dbpageNext, /* xNext - advance a cursor */
+ dbpageEof, /* xEof - check for end of scan */
+ dbpageColumn, /* xColumn - read data */
+ dbpageRowid, /* xRowid - read data */
+ dbpageUpdate, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ };
+ return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
+}
+#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
+int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
+#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
diff --git a/third_party/sqlite/src/src/delete.c b/third_party/sqlite/src/src/delete.c
index 79e0467..2d3a9b7 100644
--- a/third_party/sqlite/src/src/delete.c
+++ b/third_party/sqlite/src/src/delete.c
@@ -502,7 +502,11 @@ void sqlite3DeleteFrom(
}
}else if( pPk ){
addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
+ if( IsVirtual(pTab) ){
+ sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
+ }
assert( nKey==0 ); /* OP_Found will use a composite key */
}else{
addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
diff --git a/third_party/sqlite/src/src/expr.c b/third_party/sqlite/src/src/expr.c
index 3acf3d35..325fced 100644
--- a/third_party/sqlite/src/src/expr.c
+++ b/third_party/sqlite/src/src/expr.c
@@ -124,6 +124,11 @@ Expr *sqlite3ExprSkipCollate(Expr *pExpr){
** Return the collation sequence for the expression pExpr. If
** there is no defined collating sequence, return NULL.
**
+** See also: sqlite3ExprNNCollSeq()
+**
+** The sqlite3ExprNNCollSeq() works the same exact that it returns the
+** default collation if pExpr has no defined collation.
+**
** The collating sequence might be determined by a COLLATE operator
** or by the presence of a column with a defined collating sequence.
** COLLATE operators take first precedence. Left operands take
@@ -189,6 +194,32 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
}
/*
+** Return the collation sequence for the expression pExpr. If
+** there is no defined collating sequence, return a pointer to the
+** defautl collation sequence.
+**
+** See also: sqlite3ExprCollSeq()
+**
+** The sqlite3ExprCollSeq() routine works the same except that it
+** returns NULL if there is no defined collation.
+*/
+CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr){
+ CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr);
+ if( p==0 ) p = pParse->db->pDfltColl;
+ assert( p!=0 );
+ return p;
+}
+
+/*
+** Return TRUE if the two expressions have equivalent collating sequences.
+*/
+int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){
+ CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1);
+ CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2);
+ return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0;
+}
+
+/*
** pExpr is an operand of a comparison operator. aff2 is the
** type affinity of the other operand. This routine returns the
** type affinity that should be used for the comparison operator.
@@ -775,7 +806,7 @@ Expr *sqlite3Expr(
){
Token x;
x.z = zToken;
- x.n = zToken ? sqlite3Strlen30(zToken) : 0;
+ x.n = sqlite3Strlen30(zToken);
return sqlite3ExprAlloc(db, op, &x, 0);
}
@@ -1302,10 +1333,9 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
Expr *pPriorSelectCol = 0;
assert( db!=0 );
if( p==0 ) return 0;
- pNew = sqlite3DbMallocRawNN(db,
- sizeof(*pNew)+sizeof(pNew->a[0])*(p->nExpr-1) );
+ pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p));
if( pNew==0 ) return 0;
- pNew->nAlloc = pNew->nExpr = p->nExpr;
+ pNew->nExpr = p->nExpr;
pItem = pNew->a;
pOldItem = p->a;
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
@@ -1459,6 +1489,13 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
** Add a new element to the end of an expression list. If pList is
** initially NULL, then create a new expression list.
**
+** The pList argument must be either NULL or a pointer to an ExprList
+** obtained from a prior call to sqlite3ExprListAppend(). This routine
+** may not be used with an ExprList obtained from sqlite3ExprListDup().
+** Reason: This routine assumes that the number of slots in pList->a[]
+** is a power of two. That is true for sqlite3ExprListAppend() returns
+** but is not necessarily true from the return value of sqlite3ExprListDup().
+**
** If a memory allocation error occurs, the entire list is freed and
** NULL is returned. If non-NULL is returned, then it is guaranteed
** that the new entry was successfully appended.
@@ -1477,16 +1514,14 @@ ExprList *sqlite3ExprListAppend(
goto no_mem;
}
pList->nExpr = 0;
- pList->nAlloc = 1;
- }else if( pList->nExpr==pList->nAlloc ){
+ }else if( (pList->nExpr & (pList->nExpr-1))==0 ){
ExprList *pNew;
pNew = sqlite3DbRealloc(db, pList,
- sizeof(*pList)+(2*pList->nAlloc - 1)*sizeof(pList->a[0]));
+ sizeof(*pList)+(2*pList->nExpr - 1)*sizeof(pList->a[0]));
if( pNew==0 ){
goto no_mem;
}
pList = pNew;
- pList->nAlloc *= 2;
}
pItem = &pList->a[pList->nExpr++];
assert( offsetof(struct ExprList_item,zName)==sizeof(pItem->pExpr) );
@@ -1677,17 +1712,29 @@ void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
u32 sqlite3ExprListFlags(const ExprList *pList){
int i;
u32 m = 0;
- if( pList ){
- for(i=0; i<pList->nExpr; i++){
- Expr *pExpr = pList->a[i].pExpr;
- assert( pExpr!=0 );
- m |= pExpr->flags;
- }
+ assert( pList!=0 );
+ for(i=0; i<pList->nExpr; i++){
+ Expr *pExpr = pList->a[i].pExpr;
+ assert( pExpr!=0 );
+ m |= pExpr->flags;
}
return m;
}
/*
+** This is a SELECT-node callback for the expression walker that
+** always "fails". By "fail" in this case, we mean set
+** pWalker->eCode to zero and abort.
+**
+** This callback is used by multiple expression walkers.
+*/
+int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){
+ UNUSED_PARAMETER(NotUsed);
+ pWalker->eCode = 0;
+ return WRC_Abort;
+}
+
+/*
** These routines are Walker callbacks used to check expressions to
** see if they are "constant" for some definition of constant. The
** Walker.eCode value determines the type of "constant" we are looking
@@ -1763,21 +1810,16 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
}
/* Fall through */
default:
- testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */
- testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */
+ testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail will disallow */
+ testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail will disallow */
return WRC_Continue;
}
}
-static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
- UNUSED_PARAMETER(NotUsed);
- pWalker->eCode = 0;
- return WRC_Abort;
-}
static int exprIsConst(Expr *p, int initFlag, int iCur){
Walker w;
w.eCode = initFlag;
w.xExprCallback = exprNodeIsConstant;
- w.xSelectCallback = selectNodeIsConstant;
+ w.xSelectCallback = sqlite3SelectWalkFail;
#ifdef SQLITE_DEBUG
w.xSelectCallback2 = sqlite3SelectWalkAssert2;
#endif
@@ -1831,8 +1873,8 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
for(i=0; i<pGroupBy->nExpr; i++){
Expr *p = pGroupBy->a[i].pExpr;
if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){
- CollSeq *pColl = sqlite3ExprCollSeq(pWalker->pParse, p);
- if( pColl==0 || sqlite3_stricmp("BINARY", pColl->zName)==0 ){
+ CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p);
+ if( sqlite3_stricmp("BINARY", pColl->zName)==0 ){
return WRC_Prune;
}
}
@@ -1900,7 +1942,7 @@ int sqlite3ExprContainsSubquery(Expr *p){
Walker w;
w.eCode = 1;
w.xExprCallback = sqlite3ExprWalkNoop;
- w.xSelectCallback = selectNodeIsConstant;
+ w.xSelectCallback = sqlite3SelectWalkFail;
#ifdef SQLITE_DEBUG
w.xSelectCallback2 = sqlite3SelectWalkAssert2;
#endif
@@ -1973,8 +2015,8 @@ int sqlite3ExprCanBeNull(const Expr *p){
case TK_BLOB:
return 0;
case TK_COLUMN:
- assert( p->pTab!=0 );
return ExprHasProperty(p, EP_CanBeNull) ||
+ p->pTab==0 || /* Reference to column of index on expression */
(p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0);
default:
return 1;
@@ -2636,7 +2678,7 @@ int sqlite3CodeSubselect(
/* Loop through each expression in <exprlist>. */
r1 = sqlite3GetTempReg(pParse);
r2 = sqlite3GetTempReg(pParse);
- if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
+ if( isRowid ) sqlite3VdbeAddOp4(v, OP_Blob, 0, r2, 0, "", P4_STATIC);
for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
Expr *pE2 = pItem->pExpr;
int iValToIns;
@@ -3064,7 +3106,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
const char *z = pExpr->u.zToken;
assert( z!=0 );
c = sqlite3DecOrHexToI64(z, &value);
- if( c==1 || (c==2 && !negFlag) || (negFlag && value==SMALLEST_INT64)){
+ if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){
#ifdef SQLITE_OMIT_FLOATING_POINT
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
#else
@@ -3078,7 +3120,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
}
#endif
}else{
- if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
+ if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; }
sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
}
}
@@ -4233,7 +4275,9 @@ void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
** Generate code that pushes the value of every element of the given
** expression list into a sequence of registers beginning at target.
**
-** Return the number of elements evaluated.
+** Return the number of elements evaluated. The number returned will
+** usually be pList->nExpr but might be reduced if SQLITE_ECEL_OMITREF
+** is defined.
**
** The SQLITE_ECEL_DUP flag prevents the arguments from being
** filled using OP_SCopy. OP_Copy must be used instead.
@@ -4244,6 +4288,8 @@ void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
** The SQLITE_ECEL_REF flag means that expressions in the list with
** ExprList.a[].u.x.iOrderByCol>0 have already been evaluated and stored
** in registers at srcReg, and so the value can be copied from there.
+** If SQLITE_ECEL_OMITREF is also set, then the values with u.x.iOrderByCol>0
+** are simply omitted rather than being copied from srcReg.
*/
int sqlite3ExprCodeExprList(
Parse *pParse, /* Parsing context */
diff --git a/third_party/sqlite/src/src/func.c b/third_party/sqlite/src/src/func.c
index b85143e..6f3f02b 100644
--- a/third_party/sqlite/src/src/func.c
+++ b/third_party/sqlite/src/src/func.c
@@ -865,7 +865,8 @@ static void likeFunc(
#ifdef SQLITE_TEST
sqlite3_like_count++;
#endif
- sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH);
+ sqlite3_result_int(context,
+ patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH);
}
}
@@ -1706,9 +1707,14 @@ 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
-** return TRUE. If the function is not a LIKE-style function then
-** return FALSE.
+** 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
+** LIKE-style function then return FALSE.
+**
+** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE
+** operator if c is a string literal that is exactly one byte in length.
+** That one byte is stored in aWc[3]. aWc[3] is set to zero if there is
+** no ESCAPE clause.
**
** *pIsNocase is set to true if uppercase and lowercase are equivalent for
** the function (default for LIKE). If the function makes the distinction
@@ -1717,17 +1723,26 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
*/
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
- if( pExpr->op!=TK_FUNCTION
- || !pExpr->x.pList
- || pExpr->x.pList->nExpr!=2
- ){
+ int nExpr;
+ if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0);
+ nExpr = pExpr->x.pList->nExpr;
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
+ if( nExpr<3 ){
+ aWc[3] = 0;
+ }else{
+ Expr *pEscape = pExpr->x.pList->a[2].pExpr;
+ char *zEscape;
+ if( pEscape->op!=TK_STRING ) return 0;
+ zEscape = pEscape->u.zToken;
+ if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
+ aWc[3] = zEscape[0];
+ }
/* The memcpy() statement assumes that the wildcard characters are
** the first three statements in the compareInfo structure. The
diff --git a/third_party/sqlite/src/src/global.c b/third_party/sqlite/src/src/global.c
index e309aa4..395ca06 100644
--- a/third_party/sqlite/src/src/global.c
+++ b/third_party/sqlite/src/src/global.c
@@ -199,6 +199,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_THREADSAFE==1, /* bFullMutex */
SQLITE_USE_URI, /* bOpenUri */
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
+ 0, /* bSmallMalloc */
0x7ffffffe, /* mxStrlen */
0, /* neverCorrupt */
SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
@@ -211,9 +212,6 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, 0, /* mnHeap, mxHeap */
SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */
SQLITE_MAX_MMAP_SIZE, /* mxMmap */
- (void*)0, /* pScratch */
- 0, /* szScratch */
- 0, /* nScratch */
(void*)0, /* pPage */
0, /* szPage */
SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */
diff --git a/third_party/sqlite/src/src/insert.c b/third_party/sqlite/src/src/insert.c
index 8ce1cdd..6a45497 100644
--- a/third_party/sqlite/src/src/insert.c
+++ b/third_party/sqlite/src/src/insert.c
@@ -226,7 +226,7 @@ static int autoIncBegin(
){
int memId = 0; /* Register holding maximum rowid */
if( (pTab->tabFlags & TF_Autoincrement)!=0
- && (pParse->db->flags & SQLITE_Vacuum)==0
+ && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0
){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
AutoincInfo *pInfo;
@@ -484,7 +484,6 @@ void sqlite3Insert(
){
sqlite3 *db; /* The main database structure */
Table *pTab; /* The table to insert into. aka TABLE */
- char *zTab; /* Name of the table into which we are inserting */
int i, j; /* Loop counters */
Vdbe *v; /* Generate code into this virtual machine */
Index *pIdx; /* For looping over indices of the table */
@@ -540,8 +539,6 @@ void sqlite3Insert(
/* Locate the table into which we will be inserting new information.
*/
assert( pTabList->nSrc==1 );
- zTab = pTabList->a[0].zName;
- if( NEVER(zTab==0) ) goto insert_cleanup;
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ){
goto insert_cleanup;
@@ -2058,7 +2055,7 @@ static int xferOptimization(
Column *pDestCol = &pDest->aCol[i];
Column *pSrcCol = &pSrc->aCol[i];
#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
- if( (db->flags & SQLITE_Vacuum)==0
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0
&& (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
){
return 0; /* Neither table may have __hidden__ columns */
@@ -2134,15 +2131,15 @@ static int xferOptimization(
regRowid = sqlite3GetTempReg(pParse);
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
assert( HasRowid(pDest) || destHasUniqueIdx );
- if( (db->flags & SQLITE_Vacuum)==0 && (
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (
(pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
|| destHasUniqueIdx /* (2) */
|| (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */
)){
/* In some circumstances, we are able to run the xfer optimization
** only if the destination table is initially empty. Unless the
- ** SQLITE_Vacuum flag is set, this block generates code to make
- ** that determination. If SQLITE_Vacuum is set, then the destination
+ ** DBFLAG_Vacuum flag is set, this block generates code to make
+ ** that determination. If DBFLAG_Vacuum is set, then the destination
** table is always empty.
**
** Conditions under which the destination must be empty:
@@ -2178,8 +2175,8 @@ static int xferOptimization(
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
}
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
- if( db->flags & SQLITE_Vacuum ){
- sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
+ if( db->mDbFlags & DBFLAG_Vacuum ){
+ sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|
OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
}else{
@@ -2210,13 +2207,13 @@ static int xferOptimization(
VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
- if( db->flags & SQLITE_Vacuum ){
+ 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
** order. In this case, instead of seeking within the b-tree as part
- ** of every OP_IdxInsert opcode, an OP_Last is added before the
+ ** 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
** should be inserted. This is faster.
**
@@ -2231,7 +2228,7 @@ static int xferOptimization(
}
if( i==pSrcIdx->nColumn ){
idxInsFlags = OPFLAG_USESEEKRESULT;
- sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
+ sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
}
}
if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
diff --git a/third_party/sqlite/src/src/main.c b/third_party/sqlite/src/src/main.c
index 0b8c18d..0709b3a 100644
--- a/third_party/sqlite/src/src/main.c
+++ b/third_party/sqlite/src/src/main.c
@@ -47,9 +47,11 @@ const char sqlite3_version[] = SQLITE_VERSION;
*/
const char *sqlite3_libversion(void){ return sqlite3_version; }
-/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a
+/* IMPLEMENTATION-OF: R-25063-23286 The sqlite3_sourceid() function returns a
** pointer to a string constant whose value is the same as the
-** SQLITE_SOURCE_ID C preprocessor macro.
+** 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.
*/
const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
@@ -436,14 +438,8 @@ int sqlite3_config(int op, ...){
sqlite3GlobalConfig.bMemstat = va_arg(ap, int);
break;
}
- case SQLITE_CONFIG_SCRATCH: {
- /* EVIDENCE-OF: R-08404-60887 There are three arguments to
- ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from
- ** which the scratch allocations will be drawn, the size of each scratch
- ** allocation (sz), and the maximum number of scratch allocations (N). */
- sqlite3GlobalConfig.pScratch = va_arg(ap, void*);
- sqlite3GlobalConfig.szScratch = va_arg(ap, int);
- sqlite3GlobalConfig.nScratch = va_arg(ap, int);
+ case SQLITE_CONFIG_SMALL_MALLOC: {
+ sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int);
break;
}
case SQLITE_CONFIG_PAGECACHE: {
@@ -664,7 +660,8 @@ int sqlite3_config(int op, ...){
static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
#ifndef SQLITE_OMIT_LOOKASIDE
void *pStart;
- if( db->lookaside.nOut ){
+
+ if( sqlite3LookasideUsed(db,0)>0 ){
return SQLITE_BUSY;
}
/* Free any existing lookaside buffer for this handle before
@@ -692,16 +689,18 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
pStart = pBuf;
}
db->lookaside.pStart = pStart;
+ db->lookaside.pInit = 0;
db->lookaside.pFree = 0;
db->lookaside.sz = (u16)sz;
if( pStart ){
int i;
LookasideSlot *p;
assert( sz > (int)sizeof(LookasideSlot*) );
+ db->lookaside.nSlot = cnt;
p = (LookasideSlot*)pStart;
for(i=cnt-1; i>=0; i--){
- p->pNext = db->lookaside.pFree;
- db->lookaside.pFree = p;
+ p->pNext = db->lookaside.pInit;
+ db->lookaside.pInit = p;
p = (LookasideSlot*)&((u8*)p)[sz];
}
db->lookaside.pEnd = p;
@@ -712,6 +711,7 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
db->lookaside.pEnd = db;
db->lookaside.bDisable = 1;
db->lookaside.bMalloced = 0;
+ db->lookaside.nSlot = 0;
}
#endif /* SQLITE_OMIT_LOOKASIDE */
return SQLITE_OK;
@@ -824,7 +824,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
if( aFlagOp[i].op==op ){
int onoff = va_arg(ap, int);
int *pRes = va_arg(ap, int*);
- int oldFlags = db->flags;
+ u32 oldFlags = db->flags;
if( onoff>0 ){
db->flags |= aFlagOp[i].mask;
}else if( onoff==0 ){
@@ -1231,7 +1231,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
sqlite3_mutex_leave(db->mutex);
db->magic = SQLITE_MAGIC_CLOSED;
sqlite3_mutex_free(db->mutex);
- assert( db->lookaside.nOut==0 ); /* Fails on a lookaside memory leak */
+ assert( sqlite3LookasideUsed(db,0)==0 );
if( db->lookaside.bMalloced ){
sqlite3_free(db->lookaside.pStart);
}
@@ -1259,7 +1259,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
** the database rollback and schema reset, which can cause false
** corruption reports in some cases. */
sqlite3BtreeEnterAll(db);
- schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0;
+ schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0;
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
@@ -1273,7 +1273,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
sqlite3VtabRollback(db);
sqlite3EndBenignMalloc();
- if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
+ if( (db->mDbFlags&DBFLAG_SchemaChange)!=0 && db->init.busy==0 ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
}
@@ -2175,7 +2175,8 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
** checkpointed. If an error is encountered it is returned immediately -
** no attempt is made to checkpoint any remaining databases.
**
-** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
+** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART
+** or TRUNCATE.
*/
int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){
int rc = SQLITE_OK; /* Return code */
@@ -3061,6 +3062,12 @@ static int openDatabase(
}
#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);
@@ -3720,7 +3727,7 @@ int sqlite3_test_control(int op, ...){
** This action provides a run-time test to see how the ALWAYS and
** NEVER macros were defined at compile-time.
**
- ** The return value is ALWAYS(X).
+ ** The return value is ALWAYS(X) if X is true, or 0 if X is false.
**
** The recommended test is X==2. If the return value is 2, that means
** ALWAYS() and NEVER() are both no-op pass-through macros, which is the
@@ -3743,7 +3750,7 @@ int sqlite3_test_control(int op, ...){
*/
case SQLITE_TESTCTRL_ALWAYS: {
int x = va_arg(ap,int);
- rc = ALWAYS(x);
+ rc = x ? ALWAYS(x) : 0;
break;
}
@@ -3810,22 +3817,6 @@ int sqlite3_test_control(int op, ...){
}
#endif
- /* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree);
- **
- ** Pass pFree into sqlite3ScratchFree().
- ** If sz>0 then allocate a scratch buffer into pNew.
- */
- case SQLITE_TESTCTRL_SCRATCHMALLOC: {
- void *pFree, **ppNew;
- int sz;
- sz = va_arg(ap, int);
- ppNew = va_arg(ap, void**);
- pFree = va_arg(ap, void*);
- if( sz ) *ppNew = sqlite3ScratchMalloc(sz);
- sqlite3ScratchFree(pFree);
- break;
- }
-
/* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
**
** If parameter onoff is non-zero, configure the wrappers so that all
@@ -3967,7 +3958,7 @@ sqlite3_int64 sqlite3_uri_int64(
){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
sqlite3_int64 v;
- if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){
+ if( z && sqlite3DecOrHexToI64(z, &v)==0 ){
bDflt = v;
}
return bDflt;
diff --git a/third_party/sqlite/src/src/malloc.c b/third_party/sqlite/src/src/malloc.c
index 42a2716..20857cf 100644
--- a/third_party/sqlite/src/src/malloc.c
+++ b/third_party/sqlite/src/src/malloc.c
@@ -33,14 +33,6 @@ int sqlite3_release_memory(int n){
}
/*
-** An instance of the following object records the location of
-** each unused scratch buffer.
-*/
-typedef struct ScratchFreeslot {
- struct ScratchFreeslot *pNext; /* Next unused scratch buffer */
-} ScratchFreeslot;
-
-/*
** State information local to the memory allocation subsystem.
*/
static SQLITE_WSD struct Mem0Global {
@@ -48,21 +40,11 @@ static SQLITE_WSD struct Mem0Global {
sqlite3_int64 alarmThreshold; /* The soft heap limit */
/*
- ** Pointers to the end of sqlite3GlobalConfig.pScratch memory
- ** (so that a range test can be used to determine if an allocation
- ** being freed came from pScratch) and a pointer to the list of
- ** unused scratch allocations.
- */
- void *pScratchEnd;
- ScratchFreeslot *pScratchFree;
- u32 nScratchFree;
-
- /*
** True if heap is nearly "full" where "full" is defined by the
** sqlite3_soft_heap_limit() setting.
*/
int nearlyFull;
-} mem0 = { 0, 0, 0, 0, 0, 0 };
+} mem0 = { 0, 0, 0 };
#define mem0 GLOBAL(struct Mem0Global, mem0)
@@ -132,28 +114,6 @@ int sqlite3MallocInit(void){
}
memset(&mem0, 0, sizeof(mem0));
mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
- if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
- && sqlite3GlobalConfig.nScratch>0 ){
- int i, n, sz;
- ScratchFreeslot *pSlot;
- sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch);
- sqlite3GlobalConfig.szScratch = sz;
- pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch;
- n = sqlite3GlobalConfig.nScratch;
- mem0.pScratchFree = pSlot;
- mem0.nScratchFree = n;
- for(i=0; i<n-1; i++){
- pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot);
- pSlot = pSlot->pNext;
- }
- pSlot->pNext = 0;
- mem0.pScratchEnd = (void*)&pSlot[1];
- }else{
- mem0.pScratchEnd = 0;
- sqlite3GlobalConfig.pScratch = 0;
- sqlite3GlobalConfig.szScratch = 0;
- sqlite3GlobalConfig.nScratch = 0;
- }
if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
|| sqlite3GlobalConfig.nPage<=0 ){
sqlite3GlobalConfig.pPage = 0;
@@ -305,105 +265,6 @@ void *sqlite3_malloc64(sqlite3_uint64 n){
}
/*
-** Each thread may only have a single outstanding allocation from
-** xScratchMalloc(). We verify this constraint in the single-threaded
-** case by setting scratchAllocOut to 1 when an allocation
-** is outstanding clearing it when the allocation is freed.
-*/
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
-static int scratchAllocOut = 0;
-#endif
-
-
-/*
-** Allocate memory that is to be used and released right away.
-** This routine is similar to alloca() in that it is not intended
-** for situations where the memory might be held long-term. This
-** routine is intended to get memory to old large transient data
-** structures that would not normally fit on the stack of an
-** embedded processor.
-*/
-void *sqlite3ScratchMalloc(int n){
- void *p;
- assert( n>0 );
-
- sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusHighwater(SQLITE_STATUS_SCRATCH_SIZE, n);
- if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){
- p = mem0.pScratchFree;
- mem0.pScratchFree = mem0.pScratchFree->pNext;
- mem0.nScratchFree--;
- sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1);
- sqlite3_mutex_leave(mem0.mutex);
- }else{
- sqlite3_mutex_leave(mem0.mutex);
- p = sqlite3Malloc(n);
- if( sqlite3GlobalConfig.bMemstat && p ){
- sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
- sqlite3_mutex_leave(mem0.mutex);
- }
- sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
- }
- assert( sqlite3_mutex_notheld(mem0.mutex) );
-
-
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch
- ** buffers per thread.
- **
- ** This can only be checked in single-threaded mode.
- */
- assert( scratchAllocOut==0 );
- if( p ) scratchAllocOut++;
-#endif
-
- return p;
-}
-void sqlite3ScratchFree(void *p){
- if( p ){
-
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than two scratch allocation per thread
- ** is outstanding at one time. (This is only checked in the
- ** single-threaded case since checking in the multi-threaded case
- ** would be much more complicated.) */
- assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
- scratchAllocOut--;
-#endif
-
- if( SQLITE_WITHIN(p, sqlite3GlobalConfig.pScratch, mem0.pScratchEnd) ){
- /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */
- ScratchFreeslot *pSlot;
- pSlot = (ScratchFreeslot*)p;
- sqlite3_mutex_enter(mem0.mutex);
- pSlot->pNext = mem0.pScratchFree;
- mem0.pScratchFree = pSlot;
- mem0.nScratchFree++;
- assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
- sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1);
- sqlite3_mutex_leave(mem0.mutex);
- }else{
- /* Release memory back to the heap */
- assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
- assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) );
- sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
- if( sqlite3GlobalConfig.bMemstat ){
- int iSize = sqlite3MallocSize(p);
- sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize);
- sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize);
- sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
- sqlite3GlobalConfig.m.xFree(p);
- sqlite3_mutex_leave(mem0.mutex);
- }else{
- sqlite3GlobalConfig.m.xFree(p);
- }
- }
- }
-}
-
-/*
** TRUE if p is a lookaside memory allocation from db
*/
#ifndef SQLITE_OMIT_LOOKASIDE
@@ -493,7 +354,6 @@ void sqlite3DbFreeNN(sqlite3 *db, void *p){
#endif
pBuf->pNext = db->lookaside.pFree;
db->lookaside.pFree = pBuf;
- db->lookaside.nOut--;
return;
}
}
@@ -654,16 +514,16 @@ void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
assert( db->mallocFailed==0 );
if( n>db->lookaside.sz ){
db->lookaside.anStat[1]++;
- }else if( (pBuf = db->lookaside.pFree)==0 ){
- db->lookaside.anStat[2]++;
- }else{
+ }else if( (pBuf = db->lookaside.pFree)!=0 ){
db->lookaside.pFree = pBuf->pNext;
- db->lookaside.nOut++;
db->lookaside.anStat[0]++;
- if( db->lookaside.nOut>db->lookaside.mxOut ){
- db->lookaside.mxOut = db->lookaside.nOut;
- }
return (void*)pBuf;
+ }else if( (pBuf = db->lookaside.pInit)!=0 ){
+ db->lookaside.pInit = pBuf->pNext;
+ db->lookaside.anStat[0]++;
+ return (void*)pBuf;
+ }else{
+ db->lookaside.anStat[2]++;
}
}else if( db->mallocFailed ){
return 0;
diff --git a/third_party/sqlite/src/src/memjournal.c b/third_party/sqlite/src/src/memjournal.c
index 9753199..66e5f755 100644
--- a/third_party/sqlite/src/src/memjournal.c
+++ b/third_party/sqlite/src/src/memjournal.c
@@ -96,7 +96,8 @@ static int memjrnlRead(
int iChunkOffset;
FileChunk *pChunk;
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
if( (iAmt+iOfst)>p->endpoint.iOffset ){
return SQLITE_IOERR_SHORT_READ;
}
@@ -215,7 +216,8 @@ static int memjrnlWrite(
** 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 );
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
if( iOfst==0 && p->pFirst ){
assert( p->nChunkSize>iAmt );
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
@@ -384,17 +386,31 @@ void sqlite3MemJournalOpen(sqlite3_file *pJfd){
sqlite3JournalOpen(0, 0, pJfd, 0, -1);
}
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#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
** in-memory-only journal file (i.e. is one that was opened with a +ve
-** nSpill parameter), and the underlying file has not yet been created,
-** create it now.
+** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying
+** file has not yet been created, create it now.
*/
-int sqlite3JournalCreate(sqlite3_file *p){
+int sqlite3JournalCreate(sqlite3_file *pJfd){
int rc = SQLITE_OK;
- if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
- rc = memjrnlCreateFile((MemJournal*)p);
+ MemJournal *p = (MemJournal*)pJfd;
+ if( p->pMethod==&MemJournalMethods && (
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ p->nSpill>0
+#else
+ /* While this appears to not be possible without ATOMIC_WRITE, the
+ ** paths are complex, so it seems prudent to leave the test in as
+ ** a NEVER(), in case our analysis is subtly flawed. */
+ NEVER(p->nSpill>0)
+#endif
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ || (p->flags & SQLITE_OPEN_MAIN_JOURNAL)
+#endif
+ )){
+ rc = memjrnlCreateFile(p);
}
return rc;
}
diff --git a/third_party/sqlite/src/src/os.c b/third_party/sqlite/src/src/os.c
index 5cf0014..26c8065 100644
--- a/third_party/sqlite/src/src/os.c
+++ b/third_party/sqlite/src/src/os.c
@@ -98,7 +98,7 @@ int sqlite3OsTruncate(sqlite3_file *id, i64 size){
}
int sqlite3OsSync(sqlite3_file *id, int flags){
DO_OS_MALLOC_TEST(id);
- return id->pMethods->xSync(id, flags);
+ return flags ? id->pMethods->xSync(id, flags) : SQLITE_OK;
}
int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
DO_OS_MALLOC_TEST(id);
@@ -153,6 +153,7 @@ int sqlite3OsSectorSize(sqlite3_file *id){
int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
return id->pMethods->xDeviceCharacteristics(id);
}
+#ifndef SQLITE_OMIT_WAL
int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
return id->pMethods->xShmLock(id, offset, n, flags);
}
@@ -172,6 +173,7 @@ int sqlite3OsShmMap(
DO_OS_MALLOC_TEST(id);
return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
}
+#endif /* SQLITE_OMIT_WAL */
#if SQLITE_MAX_MMAP_SIZE>0
/* The real implementation of xFetch and xUnfetch */
diff --git a/third_party/sqlite/src/src/os.h b/third_party/sqlite/src/src/os.h
index 52d3a49..e6d9a8b 100644
--- a/third_party/sqlite/src/src/os.h
+++ b/third_party/sqlite/src/src/os.h
@@ -174,10 +174,12 @@ void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
int sqlite3OsSectorSize(sqlite3_file *id);
int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
+#ifndef SQLITE_OMIT_WAL
int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
void sqlite3OsShmBarrier(sqlite3_file *id);
int sqlite3OsShmUnmap(sqlite3_file *id, int);
+#endif /* SQLITE_OMIT_WAL */
int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
diff --git a/third_party/sqlite/src/src/os_unix.c b/third_party/sqlite/src/src/os_unix.c
index 44f6d67..6ed6f6a 100644
--- a/third_party/sqlite/src/src/os_unix.c
+++ b/third_party/sqlite/src/src/os_unix.c
@@ -90,6 +90,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <sys/ioctl.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
@@ -209,7 +210,7 @@ struct unixFile {
unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
int lastErrno; /* The unix errno from last I/O error */
void *lockingContext; /* Locking style specific state */
- UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
+ UnixUnusedFd *pPreallocatedUnused; /* Pre-allocated UnixUnusedFd */
const char *zPath; /* Name of the file */
unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
@@ -220,10 +221,8 @@ struct unixFile {
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
void *pMapRegion; /* Memory mapped region */
#endif
-#ifdef __QNXNTO__
int sectorSize; /* Device sector size */
int deviceCharacteristics; /* Precomputed device characteristics */
-#endif
#if SQLITE_ENABLE_LOCKING_STYLE
int openFlags; /* The flags specified at open() */
#endif
@@ -328,6 +327,20 @@ static pid_t randomnessPid = 0;
# define lseek lseek64
#endif
+#ifdef __linux__
+/*
+** Linux-specific IOCTL magic numbers used for controlling F2FS
+*/
+#define F2FS_IOCTL_MAGIC 0xf5
+#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1)
+#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2)
+#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3)
+#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
+#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32)
+#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
+#endif /* __linux__ */
+
+
/*
** Different Unix systems declare open() in different ways. Same use
** open(const char*,int,mode_t). Others use open(const char*,int,...).
@@ -500,6 +513,9 @@ static struct unix_syscall {
#endif
#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
+ { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 },
+#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent)
+
}; /* End of the overrideable system calls */
@@ -1104,7 +1120,8 @@ struct unixInodeInfo {
/*
** A lists of all unixInodeInfo objects.
*/
-static unixInodeInfo *inodeList = 0;
+static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */
+static unsigned int nUnusedFd = 0; /* Total unused file descriptors */
/*
**
@@ -1214,6 +1231,7 @@ static void closePendingFds(unixFile *pFile){
pNext = p->pNext;
robust_close(pFile, p->fd, __LINE__);
sqlite3_free(p);
+ nUnusedFd--;
}
pInode->pUnused = 0;
}
@@ -1246,6 +1264,7 @@ static void releaseInodeInfo(unixFile *pFile){
sqlite3_free(pInode);
}
}
+ assert( inodeList!=0 || nUnusedFd==0 );
}
/*
@@ -1315,6 +1334,7 @@ static int findInodeInfo(
#else
fileId.ino = (u64)statbuf.st_ino;
#endif
+ assert( inodeList!=0 || nUnusedFd==0 );
pInode = inodeList;
while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
pInode = pInode->pNext;
@@ -1740,11 +1760,12 @@ end_lock:
*/
static void setPendingFd(unixFile *pFile){
unixInodeInfo *pInode = pFile->pInode;
- UnixUnusedFd *p = pFile->pUnused;
+ UnixUnusedFd *p = pFile->pPreallocatedUnused;
p->pNext = pInode->pUnused;
pInode->pUnused = p;
pFile->h = -1;
- pFile->pUnused = 0;
+ pFile->pPreallocatedUnused = 0;
+ nUnusedFd++;
}
/*
@@ -1969,7 +1990,7 @@ static int closeUnixFile(sqlite3_file *id){
#endif
OSTRACE(("CLOSE %-3d\n", pFile->h));
OpenCounter(-1);
- sqlite3_free(pFile->pUnused);
+ sqlite3_free(pFile->pPreallocatedUnused);
memset(pFile, 0, sizeof(unixFile));
return SQLITE_OK;
}
@@ -2306,7 +2327,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
+ if( (rc & 0xff) == SQLITE_IOERR ){
rc = SQLITE_OK;
reserved=1;
}
@@ -2373,7 +2394,7 @@ static int flockLock(sqlite3_file *id, int 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 & SQLITE_IOERR) == SQLITE_IOERR ){
+ if( (rc & 0xff) == SQLITE_IOERR ){
rc = SQLITE_BUSY;
}
#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
@@ -2910,7 +2931,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
/* Can't reestablish the shared lock. Sqlite can't deal, this is
** a critical I/O error
*/
- rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 :
+ rc = ((failed & 0xff) == SQLITE_IOERR) ? failed2 :
SQLITE_IOERR_LOCK;
goto afp_end_lock;
}
@@ -3190,7 +3211,7 @@ static int unixRead(
/* If this is a database file (not a journal, master-journal or temp
** file), the bytes in the locking range should never be read or written. */
#if 0
- assert( pFile->pUnused==0
+ assert( pFile->pPreallocatedUnused==0
|| offset>=PENDING_BYTE+512
|| offset+amt<=PENDING_BYTE
);
@@ -3303,7 +3324,7 @@ static int unixWrite(
/* If this is a database file (not a journal, master-journal or temp
** file), the bytes in the locking range should never be read or written. */
#if 0
- assert( pFile->pUnused==0
+ assert( pFile->pPreallocatedUnused==0
|| offset>=PENDING_BYTE+512
|| offset+amt<=PENDING_BYTE
);
@@ -3783,6 +3804,21 @@ static int unixGetTempname(int nBuf, char *zBuf);
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
unixFile *pFile = (unixFile*)id;
switch( op ){
+#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+ case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: {
+ int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE);
+ return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK;
+ }
+ case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: {
+ int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE);
+ return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK;
+ }
+ case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
+ int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
+ return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK;
+ }
+#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
+
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = pFile->eFileLock;
return SQLITE_OK;
@@ -3833,6 +3869,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
if( newLimit>sqlite3GlobalConfig.mxMmap ){
newLimit = sqlite3GlobalConfig.mxMmap;
}
+
+ /* The value of newLimit may be eventually cast to (size_t) and passed
+ ** to mmap(). Restrict its value to 2GB if (size_t) is not at least a
+ ** 64-bit type. */
+ if( newLimit>0 && sizeof(size_t)<8 ){
+ newLimit = (newLimit & 0x7FFFFFFF);
+ }
+
*(i64*)pArg = pFile->mmapSizeMax;
if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
pFile->mmapSizeMax = newLimit;
@@ -3866,30 +3910,41 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
/*
-** Return the sector size in bytes of the underlying block device for
-** the specified file. This is almost always 512 bytes, but may be
-** larger for some devices.
+** 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.
**
-** SQLite code assumes this function cannot fail. It also assumes that
-** if two files are created in the same file-system directory (i.e.
-** a database and its journal file) that the sector size will be the
-** same for both.
+** There are two versions of this function. One for QNX and one for all
+** other systems.
*/
#ifndef __QNXNTO__
-static int unixSectorSize(sqlite3_file *NotUsed){
- UNUSED_PARAMETER(NotUsed);
- return SQLITE_DEFAULT_SECTOR_SIZE;
-}
-#endif
+static void setDeviceCharacteristics(unixFile *pFd){
+ assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 );
+ if( pFd->sectorSize==0 ){
+#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+ int res;
+ u32 f = 0;
-/*
-** The following version of unixSectorSize() is optimized for QNX.
-*/
-#ifdef __QNXNTO__
+ /* Check for support for F2FS atomic batch writes. */
+ res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f);
+ if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){
+ pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC;
+ }
+#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
+
+ /* Set the POWERSAFE_OVERWRITE flag if requested. */
+ if( pFd->ctrlFlags & UNIXFILE_PSOW ){
+ pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
+ }
+
+ pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
+ }
+}
+#else
#include <sys/dcmd_blk.h>
#include <sys/statvfs.h>
-static int unixSectorSize(sqlite3_file *id){
- unixFile *pFile = (unixFile*)id;
+static void setDeviceCharacteristics(unixFile *pFile){
if( pFile->sectorSize == 0 ){
struct statvfs fsInfo;
@@ -3958,9 +4013,24 @@ static int unixSectorSize(sqlite3_file *id){
pFile->deviceCharacteristics = 0;
pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
}
- return pFile->sectorSize;
}
-#endif /* __QNXNTO__ */
+#endif
+
+/*
+** Return the sector size in bytes of the underlying block device for
+** the specified file. This is almost always 512 bytes, but may be
+** larger for some devices.
+**
+** SQLite code assumes this function cannot fail. It also assumes that
+** if two files are created in the same file-system directory (i.e.
+** a database and its journal file) that the sector size will be the
+** same for both.
+*/
+static int unixSectorSize(sqlite3_file *id){
+ unixFile *pFd = (unixFile*)id;
+ setDeviceCharacteristics(pFd);
+ return pFd->sectorSize;
+}
/*
** Return the device characteristics for the file.
@@ -3976,16 +4046,9 @@ static int unixSectorSize(sqlite3_file *id){
** available to turn it off and URI query parameter available to turn it off.
*/
static int unixDeviceCharacteristics(sqlite3_file *id){
- unixFile *p = (unixFile*)id;
- int rc = 0;
-#ifdef __QNXNTO__
- if( p->sectorSize==0 ) unixSectorSize(id);
- rc = p->deviceCharacteristics;
-#endif
- if( p->ctrlFlags & UNIXFILE_PSOW ){
- rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
- }
- return rc;
+ unixFile *pFd = (unixFile*)id;
+ setDeviceCharacteristics(pFd);
+ return pFd->deviceCharacteristics;
}
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
@@ -5243,17 +5306,6 @@ static int fillInUnixFile(
assert( pNew->pInode==NULL );
- /* Usually the path zFilename should not be a relative pathname. The
- ** exception is when opening the proxy "conch" file in builds that
- ** include the special Apple locking styles.
- */
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- assert( zFilename==0 || zFilename[0]=='/'
- || pVfs->pAppData==(void*)&autolockIoFinder );
-#else
- assert( zFilename==0 || zFilename[0]=='/' );
-#endif
-
/* No locking occurs in temporary files */
assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 );
@@ -5512,6 +5564,8 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
#if !OS_VXWORKS
struct stat sStat; /* Results of stat() call */
+ unixEnterMutex();
+
/* A stat() call may fail for various reasons. If this happens, it is
** almost certain that an open() call on the same path will also fail.
** For this reason, if an error occurs in the stat() call here, it is
@@ -5520,10 +5574,9 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
**
** Even if a subsequent open() call does succeed, the consequences of
** not searching for a reusable file descriptor are not dire. */
- if( 0==osStat(zPath, &sStat) ){
+ if( nUnusedFd>0 && 0==osStat(zPath, &sStat) ){
unixInodeInfo *pInode;
- unixEnterMutex();
pInode = inodeList;
while( pInode && (pInode->fileId.dev!=sStat.st_dev
|| pInode->fileId.ino!=(u64)sStat.st_ino) ){
@@ -5534,11 +5587,12 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
pUnused = *pp;
if( pUnused ){
+ nUnusedFd--;
*pp = pUnused->pNext;
}
}
- unixLeaveMutex();
}
+ unixLeaveMutex();
#endif /* if !OS_VXWORKS */
return pUnused;
}
@@ -5614,16 +5668,11 @@ static int findCreateFileMode(
*/
nDb = sqlite3Strlen30(zPath) - 1;
while( zPath[nDb]!='-' ){
-#ifndef SQLITE_ENABLE_8_3_NAMES
- /* In the normal case (8+3 filenames disabled) the journal filename
- ** is guaranteed to contain a '-' character. */
- assert( nDb>0 );
- assert( sqlite3Isalnum(zPath[nDb]) );
-#else
- /* If 8+3 names are possible, then the journal file might not contain
- ** a '-' character. So check for that case and return early. */
+ /* 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;
-#endif
nDb--;
}
memcpy(zDb, zPath, nDb);
@@ -5665,20 +5714,21 @@ int chromium_sqlite3_fill_in_unix_sqlite3_file(sqlite3_vfs* pVfs,
memset(p, 0, sizeof(unixFile));
/* osStat() will not work in the sandbox, so findReusableFd() will always
- ** fail, so directly include the failure-case setup then initialize pUnused.
+ ** fail, so directly include the failure-case setup then initialize
+ ** pPreallocatedUnused.
*/
if( eType==SQLITE_OPEN_MAIN_DB ){
- p->pUnused = sqlite3_malloc(sizeof(*p->pUnused));
- if (!p->pUnused) {
+ p->pPreallocatedUnused = sqlite3_malloc(sizeof(*p->pPreallocatedUnused));
+ if (!p->pPreallocatedUnused) {
return SQLITE_NOMEM_BKPT;
}
- p->pUnused->fd = fd;
- p->pUnused->flags = flags;
+ p->pPreallocatedUnused->fd = fd;
+ p->pPreallocatedUnused->flags = flags;
}
rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
if( rc!=SQLITE_OK ){
- sqlite3_free(p->pUnused);
+ sqlite3_free(p->pPreallocatedUnused);
}
return rc;
}
@@ -5799,7 +5849,7 @@ static int unixOpen(
return SQLITE_NOMEM_BKPT;
}
}
- p->pUnused = pUnused;
+ p->pPreallocatedUnused = pUnused;
/* Database filenames are double-zero terminated if they are not
** URIs with parameters. Hence, they can always be passed into
@@ -5836,7 +5886,7 @@ static int unixOpen(
gid_t gid; /* Groupid for the file */
rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
if( rc!=SQLITE_OK ){
- assert( !p->pUnused );
+ assert( !p->pPreallocatedUnused );
assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
return rc;
}
@@ -5870,10 +5920,10 @@ static int unixOpen(
*pOutFlags = flags;
}
- if( p->pUnused ){
+ if( p->pPreallocatedUnused ){
/* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
- p->pUnused->fd = fd;
- p->pUnused->flags = flags;
+ p->pPreallocatedUnused->fd = fd;
+ p->pPreallocatedUnused->flags = flags;
}
if( isDelete ){
@@ -5950,13 +6000,16 @@ static int unixOpen(
}
#endif
+ assert( zPath==0 || zPath[0]=='/'
+ || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
+ );
/* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
open_finished:
if( rc!=SQLITE_OK ){
/* Duplicated in chromium_sqlite3_fill_in_unix_sqlite3_file(). */
- sqlite3_free(p->pUnused);
+ sqlite3_free(p->pPreallocatedUnused);
}
return rc;
}
@@ -6697,7 +6750,7 @@ static int proxyCreateUnixFile(
dummyVfs.zName = "dummy";
pUnused->fd = fd;
pUnused->flags = openFlags;
- pNew->pUnused = pUnused;
+ pNew->pPreallocatedUnused = pUnused;
rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0);
if( rc==SQLITE_OK ){
@@ -7647,7 +7700,7 @@ int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==28 );
+ assert( ArraySize(aSyscall)==29 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
diff --git a/third_party/sqlite/src/src/os_win.c b/third_party/sqlite/src/src/os_win.c
index 1d9abf0..eeb2c14 100644
--- a/third_party/sqlite/src/src/os_win.c
+++ b/third_party/sqlite/src/src/os_win.c
@@ -3559,6 +3559,14 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
if( newLimit>sqlite3GlobalConfig.mxMmap ){
newLimit = sqlite3GlobalConfig.mxMmap;
}
+
+ /* The value of newLimit may be eventually cast to (SIZE_T) and passed
+ ** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at
+ ** least a 64-bit type. */
+ if( newLimit>0 && sizeof(SIZE_T)<8 ){
+ newLimit = (newLimit & 0x7FFFFFFF);
+ }
+
*(i64*)pArg = pFile->mmapSizeMax;
if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
pFile->mmapSizeMax = newLimit;
@@ -4871,6 +4879,14 @@ static int winIsDir(const void *zConverted){
return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
}
+/* forward reference */
+static int winAccess(
+ sqlite3_vfs *pVfs, /* Not used on win32 */
+ const char *zFilename, /* Name of file to check */
+ int flags, /* Type of test to make on this file */
+ int *pResOut /* OUT: Result */
+);
+
/*
** Open a file.
*/
@@ -5047,37 +5063,52 @@ static int winOpen(
extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
extendedParameters.lpSecurityAttributes = NULL;
extendedParameters.hTemplateFile = NULL;
- while( (h = osCreateFile2((LPCWSTR)zConverted,
- dwDesiredAccess,
- dwShareMode,
- dwCreationDisposition,
- &extendedParameters))==INVALID_HANDLE_VALUE &&
- winRetryIoerr(&cnt, &lastErrno) ){
- /* Noop */
- }
+ do{
+ h = osCreateFile2((LPCWSTR)zConverted,
+ dwDesiredAccess,
+ dwShareMode,
+ dwCreationDisposition,
+ &extendedParameters);
+ if( h!=INVALID_HANDLE_VALUE ) break;
+ if( isReadWrite ){
+ int isRO = 0;
+ int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ if( rc2==SQLITE_OK && isRO ) break;
+ }
+ }while( winRetryIoerr(&cnt, &lastErrno) );
#else
- while( (h = osCreateFileW((LPCWSTR)zConverted,
- dwDesiredAccess,
- dwShareMode, NULL,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- NULL))==INVALID_HANDLE_VALUE &&
- winRetryIoerr(&cnt, &lastErrno) ){
- /* Noop */
- }
+ do{
+ h = osCreateFileW((LPCWSTR)zConverted,
+ dwDesiredAccess,
+ dwShareMode, NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL);
+ if( h!=INVALID_HANDLE_VALUE ) break;
+ if( isReadWrite ){
+ int isRO = 0;
+ int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ if( rc2==SQLITE_OK && isRO ) break;
+ }
+ }while( winRetryIoerr(&cnt, &lastErrno) );
#endif
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
- while( (h = osCreateFileA((LPCSTR)zConverted,
- dwDesiredAccess,
- dwShareMode, NULL,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- NULL))==INVALID_HANDLE_VALUE &&
- winRetryIoerr(&cnt, &lastErrno) ){
- /* Noop */
- }
+ do{
+ h = osCreateFileA((LPCSTR)zConverted,
+ dwDesiredAccess,
+ dwShareMode, NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL);
+ if( h!=INVALID_HANDLE_VALUE ) break;
+ if( isReadWrite ){
+ int isRO = 0;
+ int rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ if( rc2==SQLITE_OK && isRO ) break;
+ }
+ }while( winRetryIoerr(&cnt, &lastErrno) );
}
#endif
winLogIoerr(cnt, __LINE__);
@@ -5086,8 +5117,6 @@ static int winOpen(
dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
if( h==INVALID_HANDLE_VALUE ){
- pFile->lastErrno = lastErrno;
- winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
sqlite3_free(zConverted);
sqlite3_free(zTmpname);
if( isReadWrite && !isExclusive ){
@@ -5096,6 +5125,8 @@ static int winOpen(
~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
pOutFlags);
}else{
+ pFile->lastErrno = lastErrno;
+ winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
return SQLITE_CANTOPEN_BKPT;
}
}
@@ -5688,9 +5719,6 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
EntropyGatherer e;
UNUSED_PARAMETER(pVfs);
memset(zBuf, 0, nBuf);
-#if defined(_MSC_VER) && _MSC_VER>=1400 && !SQLITE_OS_WINCE
- rand_s((unsigned int*)zBuf); /* rand_s() is not available with MinGW */
-#endif /* defined(_MSC_VER) && _MSC_VER>=1400 */
e.a = (unsigned char*)zBuf;
e.na = nBuf;
e.nXor = 0;
diff --git a/third_party/sqlite/src/src/pager.c b/third_party/sqlite/src/src/pager.c
index 8023dca..5b964f3 100644
--- a/third_party/sqlite/src/src/pager.c
+++ b/third_party/sqlite/src/src/pager.c
@@ -128,8 +128,8 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
** struct as its argument.
*/
-#define PAGERID(p) ((int)(p->fd))
-#define FILEHANDLEID(fd) ((int)fd)
+#define PAGERID(p) (SQLITE_PTR_TO_INT(p->fd))
+#define FILEHANDLEID(fd) (SQLITE_PTR_TO_INT(fd))
/*
** The Pager.eState variable stores the current 'state' of a pager. A
@@ -616,6 +616,18 @@ struct PagerSavepoint {
** 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
+**
+** syncFlags is either SQLITE_SYNC_NORMAL (0x02) or SQLITE_SYNC_FULL (0x03).
+** syncFlags is used for rollback mode. walSyncFlags is used for WAL mode
+** and contains the flags used to sync the checkpoint operations in the
+** lower two bits, and sync flags used for transaction commits in the WAL
+** file in bits 0x04 and 0x08. In other words, to get the correct sync flags
+** for checkpoint operations, use (walSyncFlags&0x03) and to get the correct
+** sync flags for transaction commit, use ((walSyncFlags>>2)&0x03). Note
+** that with synchronous=NORMAL in WAL mode, transaction commit is not synced
+** meaning that the 0x04 and 0x08 bits are both zero.
*/
struct Pager {
sqlite3_vfs *pVfs; /* OS functions to use for IO */
@@ -625,9 +637,8 @@ struct Pager {
u8 noSync; /* Do not sync the journal if true */
u8 fullSync; /* Do extra syncs of the journal for robustness */
u8 extraSync; /* sync directory after journal delete */
- u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */
- u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */
u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */
+ u8 walSyncFlags; /* See description above */
u8 tempFile; /* zFilename is a temporary or immutable file */
u8 noLock; /* Do not lock (except in WAL mode) */
u8 readOnly; /* True for a read-only database */
@@ -947,6 +958,7 @@ static int assert_pager_state(Pager *p){
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 );
break;
@@ -958,6 +970,7 @@ static int assert_pager_state(Pager *p){
assert( isOpen(p->jfd)
|| p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_WAL
+ || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
);
break;
@@ -1168,34 +1181,47 @@ static int pagerLockDb(Pager *pPager, int eLock){
}
/*
-** This function determines whether or not the atomic-write optimization
-** can be used with this pager. The optimization can be used if:
+** This function determines whether or not the atomic-write or
+** atomic-batch-write optimizations can be used with this pager. The
+** atomic-write optimization can be used if:
**
** (a) the value returned by OsDeviceCharacteristics() indicates that
** a database page may be written atomically, and
** (b) the value returned by OsSectorSize() is less than or equal
** to the page size.
**
-** The optimization is also always enabled for temporary files. It is
-** an error to call this function if pPager is opened on an in-memory
-** database.
+** 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()
+** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is
+** returned in this case.
**
-** If the optimization cannot be used, 0 is returned. 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.
+** If neither optimization can be used, 0 is returned.
*/
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
static int jrnlBufferSize(Pager *pPager){
assert( !MEMDB );
- if( !pPager->tempFile ){
- int dc; /* Device characteristics */
- int nSector; /* Sector size */
- int szPage; /* Page size */
- assert( isOpen(pPager->fd) );
- dc = sqlite3OsDeviceCharacteristics(pPager->fd);
- nSector = pPager->sectorSize;
- szPage = pPager->pageSize;
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+ int dc; /* Device characteristics */
+
+ assert( isOpen(pPager->fd) );
+ dc = sqlite3OsDeviceCharacteristics(pPager->fd);
+#else
+ UNUSED_PARAMETER(pPager);
+#endif
+
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ if( dc&SQLITE_IOCAP_BATCH_ATOMIC ){
+ return -1;
+ }
+#endif
+
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ {
+ int nSector = pPager->sectorSize;
+ int szPage = pPager->pageSize;
assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
@@ -1205,11 +1231,11 @@ static int jrnlBufferSize(Pager *pPager){
}
return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
-}
-#else
-# define jrnlBufferSize(x) 0
#endif
+ return 0;
+}
+
/*
** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
** on the cache using a hash function. This is used for testing
@@ -1291,6 +1317,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
|| szJ<16
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
|| len>=nMaster
+ || len>szJ-16
|| len==0
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
|| SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
@@ -2012,7 +2039,9 @@ 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) ){
assert( !pagerUseWal(pPager) );
@@ -2780,6 +2809,7 @@ static int pager_playback(Pager *pPager, int isHot){
char *zMaster = 0; /* Name of master 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;
/* Figure out how many records are in the journal. Abort early if
** the journal is empty.
@@ -2909,6 +2939,9 @@ static int pager_playback(Pager *pPager, int isHot){
assert( 0 );
end_playback:
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerSetPagesize(pPager, &savedPageSize, -1);
+ }
/* Following a rollback, the database file should be back in its original
** state prior to the start of the transaction, so invoke the
** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the
@@ -2967,7 +3000,8 @@ end_playback:
/*
-** Read the content for page pPg out of the database file and into
+** 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
** pPg->pData. A shared lock or greater must be held on the database
** file before this function is called.
**
@@ -2977,30 +3011,33 @@ end_playback:
** If an IO error occurs, then the IO error is returned to the caller.
** Otherwise, SQLITE_OK is returned.
*/
-static int readDbPage(PgHdr *pPg, u32 iFrame){
+static int readDbPage(PgHdr *pPg){
Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
- Pgno pgno = pPg->pgno; /* Page number to read */
int rc = SQLITE_OK; /* Return code */
- int pgsz = pPager->pageSize; /* Number of bytes to read */
+
+#ifndef SQLITE_OMIT_WAL
+ u32 iFrame = 0; /* Frame of WAL containing pgno */
assert( pPager->eState>=PAGER_READER && !MEMDB );
assert( isOpen(pPager->fd) );
-#ifndef SQLITE_OMIT_WAL
+ if( pagerUseWal(pPager) ){
+ rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
+ if( rc ) return rc;
+ }
if( iFrame ){
- /* Try to pull the page from the write-ahead log. */
- rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
+ rc = sqlite3WalReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData);
}else
#endif
{
- i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
- rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
+ i64 iOffset = (pPg->pgno-1)*(i64)pPager->pageSize;
+ rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
}
- if( pgno==1 ){
+ if( pPg->pgno==1 ){
if( rc ){
/* If the read is unsuccessful, set the dbFileVers[] to something
** that will never be a valid file version. dbFileVers[] is a copy
@@ -3020,13 +3057,13 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
}
}
- CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM_BKPT);
+ 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, pgno));
+ IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno));
PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
- PAGERID(pPager), pgno, pager_pagehash(pPg)));
+ PAGERID(pPager), pPg->pgno, pager_pagehash(pPg)));
return rc;
}
@@ -3077,11 +3114,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
if( sqlite3PcachePageRefcount(pPg)==1 ){
sqlite3PcacheDrop(pPg);
}else{
- u32 iFrame = 0;
- rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
- if( rc==SQLITE_OK ){
- rc = readDbPage(pPg, iFrame);
- }
+ rc = readDbPage(pPg);
if( rc==SQLITE_OK ){
pPager->xReiniter(pPg);
}
@@ -3587,20 +3620,17 @@ void sqlite3PagerSetFlags(
}
if( pPager->noSync ){
pPager->syncFlags = 0;
- pPager->ckptSyncFlags = 0;
}else if( pgFlags & PAGER_FULLFSYNC ){
pPager->syncFlags = SQLITE_SYNC_FULL;
- pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
- }else if( pgFlags & PAGER_CKPT_FULLFSYNC ){
- pPager->syncFlags = SQLITE_SYNC_NORMAL;
- pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
}else{
pPager->syncFlags = SQLITE_SYNC_NORMAL;
- pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
}
- pPager->walSyncFlags = pPager->syncFlags;
+ pPager->walSyncFlags = (pPager->syncFlags<<2);
if( pPager->fullSync ){
- pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
+ pPager->walSyncFlags |= pPager->syncFlags;
+ }
+ if( (pgFlags & PAGER_CKPT_FULLFSYNC) && !pPager->noSync ){
+ pPager->walSyncFlags |= (SQLITE_SYNC_FULL<<2);
}
if( pgFlags & PAGER_CACHESPILL ){
pPager->doNotSpill &= ~SPILLFLAG_OFF;
@@ -4099,7 +4129,7 @@ int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
assert( db || pPager->pWal==0 );
- sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags, pPager->pageSize,
+ sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,
(db && (db->flags & SQLITE_NoCkptOnClose) ? 0 : pTmp)
);
pPager->pWal = 0;
@@ -4568,6 +4598,13 @@ static int pagerStress(void *p, PgHdr *pPg){
}
}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
|| pPager->eState==PAGER_WRITER_CACHEMOD
@@ -4900,13 +4937,11 @@ act_like_temp_file:
assert( pPager->extraSync==0 );
assert( pPager->syncFlags==0 );
assert( pPager->walSyncFlags==0 );
- assert( pPager->ckptSyncFlags==0 );
}else{
pPager->fullSync = 1;
pPager->extraSync = 0;
pPager->syncFlags = SQLITE_SYNC_NORMAL;
- pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
- pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
+ pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2);
}
/* pPager->pFirst = 0; */
/* pPager->pFirstSynced = 0; */
@@ -5326,7 +5361,8 @@ int sqlite3PagerSharedLock(Pager *pPager){
** nothing to rollback, so this routine is a no-op.
*/
static void pagerUnlockIfUnused(Pager *pPager){
- if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
+ if( sqlite3PcacheRefCount(pPager->pPCache)==0 ){
+ assert( pPager->nMmapOut==0 ); /* because page1 is never memory mapped */
pagerUnlockAndRollback(pPager);
}
}
@@ -5467,14 +5503,9 @@ static int getPageNormal(
memset(pPg->pData, 0, pPager->pageSize);
IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{
- u32 iFrame = 0; /* Frame to read from WAL file */
- if( pagerUseWal(pPager) ){
- rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
- if( rc!=SQLITE_OK ) goto pager_acquire_err;
- }
assert( pPg->pPager==pPager );
pPager->aStat[PAGER_STAT_MISS]++;
- rc = readDbPage(pPg, iFrame);
+ rc = readDbPage(pPg);
if( rc!=SQLITE_OK ){
goto pager_acquire_err;
}
@@ -5617,25 +5648,39 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
/*
** Release a page reference.
**
-** If the number of references to the page drop to zero, then the
-** page is added to the LRU list. When all references to all pages
-** are released, a rollback occurs and the lock on the database is
-** removed.
+** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be
+** used if we know that the page being released is not the last page.
+** The btree layer always holds page1 open until the end, so these first
+** to routines can be used to release any page other than BtShared.pPage1.
+**
+** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine
+** checks the total number of outstanding pages and if the number of
+** pages reaches zero it drops the database lock.
*/
void sqlite3PagerUnrefNotNull(DbPage *pPg){
- Pager *pPager;
+ TESTONLY( Pager *pPager = pPg->pPager; )
assert( pPg!=0 );
- pPager = pPg->pPager;
if( pPg->flags & PGHDR_MMAP ){
+ assert( pPg->pgno!=1 ); /* Page1 is never memory mapped */
pagerReleaseMapPage(pPg);
}else{
sqlite3PcacheRelease(pPg);
}
- pagerUnlockIfUnused(pPager);
+ /* Do not use this routine to release the last reference to page1 */
+ assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
}
void sqlite3PagerUnref(DbPage *pPg){
if( pPg ) sqlite3PagerUnrefNotNull(pPg);
}
+void sqlite3PagerUnrefPageOne(DbPage *pPg){
+ Pager *pPager;
+ assert( pPg!=0 );
+ assert( pPg->pgno==1 );
+ assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
+ pPager = pPg->pPager;
+ sqlite3PcacheRelease(pPg);
+ pagerUnlockIfUnused(pPager);
+}
/*
** This function is called at the start of every write transaction.
@@ -6347,6 +6392,21 @@ int sqlite3PagerCommitPhaseOne(
sqlite3PcacheCleanAll(pPager->pPCache);
}
}else{
+ /* The bBatch boolean is true if the batch-atomic-write commit method
+ ** should be used. No rollback journal is created if batch-atomic-write
+ ** is enabled.
+ */
+ sqlite3_file *fd = pPager->fd;
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ const int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
+ && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
+ && !pPager->noSync
+ && sqlite3JournalIsInMemory(pPager->jfd);
+#else
+# define bBatch 0
+#endif
+
+#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
@@ -6370,33 +6430,40 @@ int sqlite3PagerCommitPhaseOne(
** in 'direct' mode. In this case the journal file will never be
** created for this transaction.
*/
- #ifdef SQLITE_ENABLE_ATOMIC_WRITE
- PgHdr *pPg;
- assert( isOpen(pPager->jfd)
- || pPager->journalMode==PAGER_JOURNALMODE_OFF
- || pPager->journalMode==PAGER_JOURNALMODE_WAL
- );
- if( !zMaster && isOpen(pPager->jfd)
- && pPager->journalOff==jrnlBufferSize(pPager)
- && pPager->dbSize>=pPager->dbOrigSize
- && (0==(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
- ** property of the host file-system, this is safe.
- */
- rc = pager_incr_changecounter(pPager, 1);
- }else{
- rc = sqlite3JournalCreate(pPager->jfd);
- if( rc==SQLITE_OK ){
- rc = pager_incr_changecounter(pPager, 0);
+ if( bBatch==0 ){
+ PgHdr *pPg;
+ assert( isOpen(pPager->jfd)
+ || pPager->journalMode==PAGER_JOURNALMODE_OFF
+ || pPager->journalMode==PAGER_JOURNALMODE_WAL
+ );
+ if( !zMaster && 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
+ ** property of the host file-system, this is safe.
+ */
+ rc = pager_incr_changecounter(pPager, 1);
+ }else{
+ rc = sqlite3JournalCreate(pPager->jfd);
+ if( rc==SQLITE_OK ){
+ rc = pager_incr_changecounter(pPager, 0);
+ }
}
}
- #else
+#else
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ if( zMaster ){
+ rc = sqlite3JournalCreate(pPager->jfd);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ }
+#endif
rc = pager_incr_changecounter(pPager, 0);
- #endif
+#endif
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* Write the master journal name into the journal file. If a master
@@ -6420,7 +6487,23 @@ int sqlite3PagerCommitPhaseOne(
rc = syncJournal(pPager, 0);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ if( bBatch ){
+ /* The pager is now in DBMOD state. But regardless of what happens
+ ** next, attempting to play the journal back into the database would
+ ** be unsafe. Close it now to make sure that does not happen. */
+ sqlite3OsClose(pPager->jfd);
+ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ }
rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
+ if( bBatch ){
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
+ }else{
+ sqlite3OsFileControl(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
+ }
+ }
+
if( rc!=SQLITE_OK ){
assert( rc!=SQLITE_IOERR_BLOCKED );
goto commit_phase_one_exit;
@@ -7321,7 +7404,7 @@ int sqlite3PagerCheckpoint(
rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode,
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
pPager->pBusyHandlerArg,
- pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
+ pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
pnLog, pnCkpt
);
}
@@ -7478,7 +7561,7 @@ int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
if( rc==SQLITE_OK && pPager->pWal ){
rc = pagerExclusiveLock(pPager);
if( rc==SQLITE_OK ){
- rc = sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags,
+ rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags,
pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0;
pagerFixMaplimit(pPager);
diff --git a/third_party/sqlite/src/src/pager.h b/third_party/sqlite/src/src/pager.h
index 3522a4e..01ea900 100644
--- a/third_party/sqlite/src/src/pager.h
+++ b/third_party/sqlite/src/src/pager.h
@@ -151,6 +151,7 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
void sqlite3PagerRef(DbPage*);
void sqlite3PagerUnref(DbPage*);
void sqlite3PagerUnrefNotNull(DbPage*);
+void sqlite3PagerUnrefPageOne(DbPage*);
/* Operations on page references. */
int sqlite3PagerWrite(DbPage*);
diff --git a/third_party/sqlite/src/src/parse.y b/third_party/sqlite/src/src/parse.y
index 81f4116..7ad42b4 100644
--- a/third_party/sqlite/src/src/parse.y
+++ b/third_party/sqlite/src/src/parse.y
@@ -192,6 +192,19 @@ columnlist ::= columnlist COMMA columnname carglist.
columnlist ::= columnname carglist.
columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
+// Declare some tokens early in order to influence their values, to
+// improve performance and reduce the executable size. The goal here is
+// to get the "jump" operations in ISNULL through ESCAPE to have numeric
+// values that are early enough so that all jump operations are clustered
+// at the beginning, but also so that the comparison tokens NE through GE
+// are as large as possible so that they are near to FUNCTION, which is a
+// token synthesized by addopcodes.tcl.
+//
+%token ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST.
+%token CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL.
+%token OR AND NOT IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ.
+%token GT LE LT GE ESCAPE.
+
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
// fallback to ID if they will not parse as their original value.
// This obviates the need for the "id" nonterminal.
diff --git a/third_party/sqlite/src/src/pcache.c b/third_party/sqlite/src/src/pcache.c
index ee6024e..9a43a59 100644
--- a/third_party/sqlite/src/src/pcache.c
+++ b/third_party/sqlite/src/src/pcache.c
@@ -191,12 +191,9 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
p->eCreate = 2;
}
}
- pPage->pDirtyNext = 0;
- pPage->pDirtyPrev = 0;
}
if( addRemove & PCACHE_DIRTYLIST_ADD ){
- assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
-
+ pPage->pDirtyPrev = 0;
pPage->pDirtyNext = p->pDirty;
if( pPage->pDirtyNext ){
assert( pPage->pDirtyNext->pDirtyPrev==0 );
@@ -513,11 +510,7 @@ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
if( (--p->nRef)==0 ){
if( p->flags&PGHDR_CLEAN ){
pcacheUnpin(p);
- }else if( p->pDirtyPrev!=0 ){ /*OPTIMIZATION-IF-FALSE*/
- /* Move the page to the head of the dirty list. If p->pDirtyPrev==0,
- ** then page p is already at the head of the dirty list and the
- ** following call would be a no-op. Hence the OPTIMIZATION-IF-FALSE
- ** tag above. */
+ }else{
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
diff --git a/third_party/sqlite/src/src/pcache.h b/third_party/sqlite/src/src/pcache.h
index 570688a..8aadd02 100644
--- a/third_party/sqlite/src/src/pcache.h
+++ b/third_party/sqlite/src/src/pcache.h
@@ -43,6 +43,8 @@ struct PgHdr {
i16 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
+ ** PgHdr object is not dirty */
};
/* Bit values for PgHdr.flags */
diff --git a/third_party/sqlite/src/src/pcache1.c b/third_party/sqlite/src/src/pcache1.c
index 4b09e98..c93294a 100644
--- a/third_party/sqlite/src/src/pcache1.c
+++ b/third_party/sqlite/src/src/pcache1.c
@@ -96,7 +96,6 @@ typedef struct PGroup PGroup;
struct PgHdr1 {
sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
unsigned int iKey; /* Key value (page number) */
- u8 isPinned; /* Page in use, not on the LRU list */
u8 isBulkLocal; /* This page from bulk local storage */
u8 isAnchor; /* This is the PGroup.lru element */
PgHdr1 *pNext; /* Next in hash table chain */
@@ -105,6 +104,12 @@ struct PgHdr1 {
PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
};
+/*
+** A page is pinned if it is no on the LRU list
+*/
+#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
** 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
@@ -132,7 +137,7 @@ struct PGroup {
unsigned int nMaxPage; /* Sum of nMax for purgeable caches */
unsigned int nMinPage; /* Sum of nMin for purgeable caches */
unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */
- unsigned int nCurrentPage; /* Number of purgeable pages allocated */
+ unsigned int nPurgeable; /* Number of purgeable pages allocated */
PgHdr1 lru; /* The beginning and end of the LRU list */
};
@@ -146,11 +151,13 @@ struct PGroup {
*/
struct PCache1 {
/* Cache configuration parameters. Page size (szPage) and the purgeable
- ** flag (bPurgeable) are set when the cache is created. nMax may be
+ ** flag (bPurgeable) and the pnPurgeable pointer are all set when the
+ ** 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.
*/
PGroup *pGroup; /* PGroup this cache belongs to */
+ unsigned int *pnPurgeable; /* Pointer to pGroup->nPurgeable */
int szPage; /* Size of database content section */
int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */
int szAlloc; /* Total size of one pcache line */
@@ -245,6 +252,7 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
if( pcache1.isInit ){
PgFreeslot *p;
if( pBuf==0 ) sz = n = 0;
+ if( n==0 ) sz = 0;
sz = ROUNDDOWN8(sz);
pcache1.szSlot = sz;
pcache1.nSlot = pcache1.nFreeSlot = n;
@@ -437,9 +445,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
p->isBulkLocal = 0;
p->isAnchor = 0;
}
- if( pCache->bPurgeable ){
- pCache->pGroup->nCurrentPage++;
- }
+ (*pCache->pnPurgeable)++;
return p;
}
@@ -460,9 +466,7 @@ static void pcache1FreePage(PgHdr1 *p){
sqlite3_free(p);
#endif
}
- if( pCache->bPurgeable ){
- pCache->pGroup->nCurrentPage--;
- }
+ (*pCache->pnPurgeable)--;
}
/*
@@ -557,22 +561,18 @@ static void pcache1ResizeHash(PCache1 *p){
** The PGroup mutex must be held when this function is called.
*/
static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
- PCache1 *pCache;
-
assert( pPage!=0 );
- assert( pPage->isPinned==0 );
- pCache = pPage->pCache;
+ assert( PAGE_IS_UNPINNED(pPage) );
assert( pPage->pLruNext );
assert( pPage->pLruPrev );
- assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
+ assert( sqlite3_mutex_held(pPage->pCache->pGroup->mutex) );
pPage->pLruPrev->pLruNext = pPage->pLruNext;
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
pPage->pLruNext = 0;
pPage->pLruPrev = 0;
- pPage->isPinned = 1;
assert( pPage->isAnchor==0 );
- assert( pCache->pGroup->lru.isAnchor==1 );
- pCache->nRecyclable--;
+ assert( pPage->pCache->pGroup->lru.isAnchor==1 );
+ pPage->pCache->nRecyclable--;
return pPage;
}
@@ -606,11 +606,11 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){
PGroup *pGroup = pCache->pGroup;
PgHdr1 *p;
assert( sqlite3_mutex_held(pGroup->mutex) );
- while( pGroup->nCurrentPage>pGroup->nMaxPage
+ while( pGroup->nPurgeable>pGroup->nMaxPage
&& (p=pGroup->lru.pLruPrev)->isAnchor==0
){
assert( p->pCache->pGroup==pGroup );
- assert( p->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
}
@@ -659,7 +659,7 @@ static void pcache1TruncateUnsafe(
if( pPage->iKey>=iLimit ){
pCache->nPage--;
*pp = pPage->pNext;
- if( !pPage->isPinned ) pcache1PinPage(pPage);
+ if( PAGE_IS_UNPINNED(pPage) ) pcache1PinPage(pPage);
pcache1FreePage(pPage);
}else{
pp = &pPage->pNext;
@@ -781,6 +781,10 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
pCache->nMin = 10;
pGroup->nMinPage += pCache->nMin;
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
+ pCache->pnPurgeable = &pGroup->nPurgeable;
+ }else{
+ static unsigned int dummyCurrentPage;
+ pCache->pnPurgeable = &dummyCurrentPage;
}
pcache1LeaveMutex(pGroup);
if( pCache->nHash==0 ){
@@ -882,7 +886,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
){
PCache1 *pOther;
pPage = pGroup->lru.pLruPrev;
- assert( pPage->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(pPage) );
pcache1RemoveFromHash(pPage, 0);
pcache1PinPage(pPage);
pOther = pPage->pCache;
@@ -890,7 +894,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
pcache1FreePage(pPage);
pPage = 0;
}else{
- pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
+ pGroup->nPurgeable -= (pOther->bPurgeable - pCache->bPurgeable);
}
}
@@ -909,7 +913,6 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
pPage->pCache = pCache;
pPage->pLruPrev = 0;
pPage->pLruNext = 0;
- pPage->isPinned = 1;
*(void **)pPage->page.pExtra = 0;
pCache->apHash[h] = pPage;
if( iKey>pCache->iMaxKey ){
@@ -995,7 +998,7 @@ static PgHdr1 *pcache1FetchNoMutex(
** Otherwise (page not in hash and createFlag!=0) continue with
** subsequent steps to try to create the page. */
if( pPage ){
- if( !pPage->isPinned ){
+ if( PAGE_IS_UNPINNED(pPage) ){
return pcache1PinPage(pPage);
}else{
return pPage;
@@ -1070,9 +1073,9 @@ static void pcache1Unpin(
** part of the PGroup LRU list.
*/
assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
- assert( pPage->isPinned==1 );
+ assert( PAGE_IS_PINNED(pPage) );
- if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
+ if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){
pcache1RemoveFromHash(pPage, 1);
}else{
/* Add the page to the PGroup LRU list. */
@@ -1081,7 +1084,6 @@ static void pcache1Unpin(
(pPage->pLruNext = *ppFirst)->pLruPrev = pPage;
*ppFirst = pPage;
pCache->nRecyclable++;
- pPage->isPinned = 0;
}
pcache1LeaveMutex(pCache->pGroup);
@@ -1225,7 +1227,7 @@ int sqlite3PcacheReleaseMemory(int nReq){
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
nFree += sqlite3MemSize(p);
#endif
- assert( p->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
}
@@ -1249,10 +1251,10 @@ void sqlite3PcacheStats(
PgHdr1 *p;
int nRecyclable = 0;
for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){
- assert( p->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(p) );
nRecyclable++;
}
- *pnCurrent = pcache1.grp.nCurrentPage;
+ *pnCurrent = pcache1.grp.nPurgeable;
*pnMax = (int)pcache1.grp.nMaxPage;
*pnMin = (int)pcache1.grp.nMinPage;
*pnRecyclable = nRecyclable;
diff --git a/third_party/sqlite/src/src/pragma.c b/third_party/sqlite/src/src/pragma.c
index fc73852..153d3f5 100644
--- a/third_party/sqlite/src/src/pragma.c
+++ b/third_party/sqlite/src/src/pragma.c
@@ -298,16 +298,16 @@ static const PragmaName *pragmaLocate(const char *zName){
/*
** Helper subroutine for PRAGMA integrity_check:
**
-** Generate code to output a single-column result row with the result
-** held in register regResult. Decrement the result count and halt if
-** the maximum number of result rows have been issued.
+** Generate code to output a single-column result row with a value of the
+** string held in register 3. Decrement the result count in register 1
+** and halt if the maximum number of result rows have been issued.
*/
-static int integrityCheckResultRow(Vdbe *v, int regResult){
+static int integrityCheckResultRow(Vdbe *v){
int addr;
- sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 1);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1);
VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
+ sqlite3VdbeAddOp0(v, OP_Halt);
return addr;
}
@@ -1255,13 +1255,11 @@ void sqlite3Pragma(
for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){
sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}
for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){
p = (FuncDef*)sqliteHashData(j);
sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 0);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}
break;
@@ -1273,7 +1271,6 @@ void sqlite3Pragma(
for(j=sqliteHashFirst(&db->aModule); j; j=sqliteHashNext(j)){
Module *pMod = (Module*)sqliteHashData(j);
sqlite3VdbeMultiLoad(v, 1, "s", pMod->zName);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}
break;
@@ -1283,7 +1280,6 @@ void sqlite3Pragma(
int i;
for(i=0; i<ArraySize(aPragmaName); i++){
sqlite3VdbeMultiLoad(v, 1, "s", aPragmaName[i].zName);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}
break;
@@ -1509,12 +1505,11 @@ void sqlite3Pragma(
/* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){
- HashElem *x;
- Hash *pTbls;
- int *aRoot;
- int cnt = 0;
- int mxIdx = 0;
- int nIdx;
+ HashElem *x; /* For looping over tables in the schema */
+ Hash *pTbls; /* Set of all tables in the schema */
+ int *aRoot; /* Array of root page numbers of all btrees */
+ int cnt = 0; /* Number of entries in aRoot[] */
+ int mxIdx = 0; /* Maximum number of indexes for any table */
if( OMIT_TEMPDB && i==1 ) continue;
if( iDb>=0 && i!=iDb ) continue;
@@ -1529,8 +1524,9 @@ void sqlite3Pragma(
assert( sqlite3SchemaMutexHeld(db, i, 0) );
pTbls = &db->aDb[i].pSchema->tblHash;
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
- Table *pTab = sqliteHashData(x);
- Index *pIdx;
+ Table *pTab = sqliteHashData(x); /* Current table */
+ Index *pIdx; /* An index on pTab */
+ int nIdx; /* Number of indexes on pTab */
if( HasRowid(pTab) ) cnt++;
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
if( nIdx>mxIdx ) mxIdx = nIdx;
@@ -1558,9 +1554,8 @@ void sqlite3Pragma(
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName),
P4_DYNAMIC);
- sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
- sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
- integrityCheckResultRow(v, 2);
+ sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3);
+ integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly.
@@ -1574,16 +1569,13 @@ void sqlite3Pragma(
int r1 = -1;
if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
- if( pTab->pCheck==0
- && (pTab->tabFlags & TF_HasNotNull)==0
- && (pTab->pIndex==0 || isQuick)
- ){
- continue; /* No additional checks needed for this table */
- }
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
sqlite3ExprCacheClear(pParse);
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
+ */
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
@@ -1604,7 +1596,7 @@ void sqlite3Pragma(
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pTab->aCol[j].zName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- integrityCheckResultRow(v, 3);
+ integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, jmp2);
}
/* Verify CHECK constraints */
@@ -1627,57 +1619,62 @@ void sqlite3Pragma(
zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
pTab->zName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- integrityCheckResultRow(v, 3);
+ integrityCheckResultRow(v);
sqlite3VdbeResolveLabel(v, addrCkOk);
sqlite3ExprCachePop(pParse);
}
sqlite3ExprListDelete(db, pCheck);
}
- /* Validate index entries for the current row */
- for(j=0, pIdx=pTab->pIndex; pIdx && !isQuick; pIdx=pIdx->pNext, j++){
- int jmp2, jmp3, jmp4, jmp5;
- int ckUniq = sqlite3VdbeMakeLabel(v);
- if( pPk==pIdx ) continue;
- r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
- pPrior, r1);
- pPrior = pIdx;
- sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */
- /* Verify that an index entry exists for the current table row */
- jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
- pIdx->nColumn); VdbeCoverage(v);
- sqlite3VdbeLoadString(v, 3, "row ");
- sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
- sqlite3VdbeLoadString(v, 4, " missing from index ");
- sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
- jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
- sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
- jmp4 = integrityCheckResultRow(v, 3);
- sqlite3VdbeJumpHere(v, jmp2);
- /* 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(v);
- int jmp6;
- int kk;
- for(kk=0; kk<pIdx->nKeyCol; kk++){
- int iCol = pIdx->aiColumn[kk];
- assert( iCol!=XN_ROWID && iCol<pTab->nCol );
- if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
- sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
- VdbeCoverage(v);
+ if( !isQuick ){ /* Omit the remaining tests for quick_check */
+ /* Sanity check on record header decoding */
+ sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3);
+ sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ /* Validate index entries for the current row */
+ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
+ int jmp2, jmp3, jmp4, jmp5;
+ int ckUniq = sqlite3VdbeMakeLabel(v);
+ if( pPk==pIdx ) continue;
+ r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
+ pPrior, r1);
+ pPrior = pIdx;
+ sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */
+ /* Verify that an index entry exists for the current table row */
+ jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
+ pIdx->nColumn); VdbeCoverage(v);
+ sqlite3VdbeLoadString(v, 3, "row ");
+ sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
+ sqlite3VdbeLoadString(v, 4, " missing from index ");
+ sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
+ jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
+ sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
+ jmp4 = integrityCheckResultRow(v);
+ sqlite3VdbeJumpHere(v, jmp2);
+ /* 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(v);
+ int jmp6;
+ int kk;
+ for(kk=0; kk<pIdx->nKeyCol; kk++){
+ int iCol = pIdx->aiColumn[kk];
+ assert( iCol!=XN_ROWID && iCol<pTab->nCol );
+ if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
+ sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
+ VdbeCoverage(v);
+ }
+ jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
+ sqlite3VdbeGoto(v, uniqOk);
+ sqlite3VdbeJumpHere(v, jmp6);
+ sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
+ pIdx->nKeyCol); VdbeCoverage(v);
+ sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
+ sqlite3VdbeGoto(v, jmp5);
+ sqlite3VdbeResolveLabel(v, uniqOk);
}
- jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
- sqlite3VdbeGoto(v, uniqOk);
- sqlite3VdbeJumpHere(v, jmp6);
- sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
- pIdx->nKeyCol); VdbeCoverage(v);
- sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
- sqlite3VdbeGoto(v, jmp5);
- sqlite3VdbeResolveLabel(v, uniqOk);
+ sqlite3VdbeJumpHere(v, jmp4);
+ sqlite3ResolvePartIdxLabel(pParse, jmp3);
}
- sqlite3VdbeJumpHere(v, jmp4);
- sqlite3ResolvePartIdxLabel(pParse, jmp3);
}
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, loopTop-1);
@@ -1689,9 +1686,9 @@ void sqlite3Pragma(
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
- sqlite3VdbeLoadString(v, 3, pIdx->zName);
- sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
- integrityCheckResultRow(v, 7);
+ sqlite3VdbeLoadString(v, 4, pIdx->zName);
+ sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
+ integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
}
}
@@ -1705,6 +1702,9 @@ void sqlite3Pragma(
{ OP_IfNotZero, 1, 4, 0}, /* 1 */
{ OP_String8, 0, 3, 0}, /* 2 */
{ OP_ResultRow, 3, 1, 0}, /* 3 */
+ { OP_Halt, 0, 0, 0}, /* 4 */
+ { OP_String8, 0, 3, 0}, /* 5 */
+ { OP_Goto, 0, 3, 0}, /* 6 */
};
VdbeOp *aOp;
@@ -1713,7 +1713,10 @@ void sqlite3Pragma(
aOp[0].p2 = 1-mxErr;
aOp[2].p4type = P4_STATIC;
aOp[2].p4.z = "ok";
+ aOp[5].p4type = P4_STATIC;
+ aOp[5].p4.z = (char*)sqlite3ErrStr(SQLITE_CORRUPT);
}
+ sqlite3VdbeChangeP3(v, 0, sqlite3VdbeCurrentAddr(v)-2);
}
}
break;
diff --git a/third_party/sqlite/src/src/prepare.c b/third_party/sqlite/src/src/prepare.c
index b209799..330cff9d 100644
--- a/third_party/sqlite/src/src/prepare.c
+++ b/third_party/sqlite/src/src/prepare.c
@@ -85,7 +85,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
rc = db->errCode;
assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = saved_iDb;
- assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 );
+ assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 );
if( SQLITE_OK!=rc ){
if( db->init.orphanTrigger ){
assert( iDb==1 );
@@ -150,6 +150,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
assert( sqlite3_mutex_held(db->mutex) );
assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
+ db->init.busy = 1;
+
/* Construct the in-memory representation schema tables (sqlite_master or
** sqlite_temp_master) by invoking the parser directly. The appropriate
** table name will be inserted automatically by the parser so we can just
@@ -158,7 +160,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
azArg[0] = zMasterName = SCHEMA_TABLE(iDb);
azArg[1] = "1";
azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
- "rootpage integer,sql text)";
+ "rootpage int,sql text)";
azArg[3] = 0;
initData.db = db;
initData.iDb = iDb;
@@ -174,10 +176,10 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
*/
pDb = &db->aDb[iDb];
if( pDb->pBt==0 ){
- if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){
- DbSetProperty(db, 1, DB_SchemaLoaded);
- }
- return SQLITE_OK;
+ assert( iDb==1 );
+ DbSetProperty(db, 1, DB_SchemaLoaded);
+ rc = SQLITE_OK;
+ goto error_out;
}
/* If there is not already a read-only (or read-write) transaction opened
@@ -336,9 +338,13 @@ initone_error_out:
sqlite3BtreeLeave(pDb->pBt);
error_out:
- if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
- sqlite3OomFault(db);
+ if( rc ){
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
+ sqlite3OomFault(db);
+ }
+ sqlite3ResetOneSchema(db, iDb);
}
+ db->init.busy = 0;
return rc;
}
@@ -354,42 +360,29 @@ error_out:
*/
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int i, rc;
- int commit_internal = !(db->flags&SQLITE_InternChanges);
+ int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);
assert( sqlite3_mutex_held(db->mutex) );
assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
assert( db->init.busy==0 );
- rc = SQLITE_OK;
- db->init.busy = 1;
ENC(db) = SCHEMA_ENC(db);
- for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
- if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
- rc = sqlite3InitOne(db, i, pzErrMsg);
- if( rc ){
- sqlite3ResetOneSchema(db, i);
- }
- }
-
- /* Once all the other databases have been initialized, load the schema
- ** for the TEMP database. This is loaded last, as the TEMP database
- ** schema may contain references to objects in other databases.
- */
-#ifndef SQLITE_OMIT_TEMPDB
- assert( db->nDb>1 );
- if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
- rc = sqlite3InitOne(db, 1, pzErrMsg);
- if( rc ){
- sqlite3ResetOneSchema(db, 1);
+ assert( db->nDb>0 );
+ /* Do the main schema first */
+ if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
+ rc = sqlite3InitOne(db, 0, pzErrMsg);
+ if( rc ) return rc;
+ }
+ /* All other schemas after the main schema. The "temp" schema must be last */
+ for(i=db->nDb-1; i>0; i--){
+ if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
+ rc = sqlite3InitOne(db, i, pzErrMsg);
+ if( rc ) return rc;
}
}
-#endif
-
- db->init.busy = 0;
- if( rc==SQLITE_OK && commit_internal ){
+ if( commit_internal ){
sqlite3CommitInternalChanges(db);
}
-
- return rc;
+ return SQLITE_OK;
}
/*
@@ -494,16 +487,14 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
** Free all memory allocations in the pParse object
*/
void sqlite3ParserReset(Parse *pParse){
- if( 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;
- }
- pParse->disableLookaside = 0;
+ 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;
}
+ pParse->disableLookaside = 0;
}
/*
@@ -689,6 +680,7 @@ static int sqlite3LockAndPrepare(
sqlite3BtreeEnterAll(db);
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
if( rc==SQLITE_SCHEMA ){
+ sqlite3ResetOneSchema(db, -1);
sqlite3_finalize(*ppStmt);
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
}
diff --git a/third_party/sqlite/src/src/printf.c b/third_party/sqlite/src/src/printf.c
index 6cca4d6..b43c08e 100644
--- a/third_party/sqlite/src/src/printf.c
+++ b/third_party/sqlite/src/src/printf.c
@@ -656,7 +656,7 @@ void sqlite3VXPrintf(
if( precision>=0 ){
for(length=0; length<precision && bufpt[length]; length++){}
}else{
- length = sqlite3Strlen30(bufpt);
+ length = 0x7fffffff & (int)strlen(bufpt);
}
break;
case etSQLESCAPE: /* Escape ' characters */
@@ -782,7 +782,6 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
}else{
char *zOld = isMalloced(p) ? p->zText : 0;
i64 szNew = p->nChar;
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
szNew += N + 1;
if( szNew+p->nChar<=p->mxAlloc ){
/* Force exponential buffer size growth as long as it does not overflow,
@@ -824,7 +823,6 @@ void sqlite3AppendChar(StrAccum *p, int N, char c){
if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){
return;
}
- assert( (p->zText==p->zBase)==!isMalloced(p) );
while( (N--)>0 ) p->zText[p->nChar++] = c;
}
@@ -842,7 +840,6 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
memcpy(&p->zText[p->nChar], z, N);
p->nChar += N;
}
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
}
/*
@@ -877,19 +874,20 @@ void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
** pointer if any kind of error was encountered.
*/
static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
+ char *zText;
assert( p->mxAlloc>0 && !isMalloced(p) );
- p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
- if( p->zText ){
- memcpy(p->zText, p->zBase, p->nChar+1);
+ zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
+ if( zText ){
+ memcpy(zText, p->zText, p->nChar+1);
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
}else{
setStrAccumError(p, STRACCUM_NOMEM);
}
- return p->zText;
+ p->zText = zText;
+ return zText;
}
char *sqlite3StrAccumFinish(StrAccum *p){
if( p->zText ){
- assert( (p->zText==p->zBase)==!isMalloced(p) );
p->zText[p->nChar] = 0;
if( p->mxAlloc>0 && !isMalloced(p) ){
return strAccumFinishRealloc(p);
@@ -902,7 +900,6 @@ char *sqlite3StrAccumFinish(StrAccum *p){
** Reset an StrAccum string. Reclaim all malloced memory.
*/
void sqlite3StrAccumReset(StrAccum *p){
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
if( isMalloced(p) ){
sqlite3DbFree(p->db, p->zText);
p->printfFlags &= ~SQLITE_PRINTF_MALLOCED;
@@ -925,11 +922,11 @@ void sqlite3StrAccumReset(StrAccum *p){
** allocations will ever occur.
*/
void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){
- p->zText = p->zBase = zBase;
+ p->zText = zBase;
p->db = db;
- p->nChar = 0;
p->nAlloc = n;
p->mxAlloc = mx;
+ p->nChar = 0;
p->accError = 0;
p->printfFlags = 0;
}
diff --git a/third_party/sqlite/src/src/resolve.c b/third_party/sqlite/src/src/resolve.c
index 3cced4b..5fa91ff 100644
--- a/third_party/sqlite/src/src/resolve.c
+++ b/third_party/sqlite/src/src/resolve.c
@@ -959,12 +959,10 @@ static int resolveCompoundOrderBy(
pOrderBy = pSelect->pOrderBy;
if( pOrderBy==0 ) return 0;
db = pParse->db;
-#if SQLITE_MAX_COLUMN
if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause");
return 1;
}
-#endif
for(i=0; i<pOrderBy->nExpr; i++){
pOrderBy->a[i].done = 0;
}
@@ -1056,12 +1054,10 @@ int sqlite3ResolveOrderGroupBy(
struct ExprList_item *pItem;
if( pOrderBy==0 || pParse->db->mallocFailed ) return 0;
-#if SQLITE_MAX_COLUMN
if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType);
return 1;
}
-#endif
pEList = pSelect->pEList;
assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
diff --git a/third_party/sqlite/src/src/select.c b/third_party/sqlite/src/src/select.c
index 09c2b87..29b2241 100644
--- a/third_party/sqlite/src/src/select.c
+++ b/third_party/sqlite/src/src/select.c
@@ -75,7 +75,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
sqlite3ExprListDelete(db, p->pOrderBy);
sqlite3ExprDelete(db, p->pLimit);
sqlite3ExprDelete(db, p->pOffset);
- if( p->pWith ) sqlite3WithDelete(db, p->pWith);
+ if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
if( bFree ) sqlite3DbFreeNN(db, p);
p = pPrior;
bFree = 1;
@@ -118,7 +118,8 @@ Select *sqlite3SelectNew(
pNew = &standin;
}
if( pEList==0 ){
- pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(pParse->db,TK_ASTERISK,0));
+ pEList = sqlite3ExprListAppend(pParse, 0,
+ sqlite3Expr(pParse->db,TK_ASTERISK,0));
}
pNew->pEList = pEList;
pNew->op = TK_SELECT;
@@ -142,7 +143,8 @@ Select *sqlite3SelectNew(
pNew->pLimit = pLimit;
pNew->pOffset = pOffset;
pNew->pWith = 0;
- assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || pParse->db->mallocFailed!=0 );
+ assert( pOffset==0 || pLimit!=0 || pParse->nErr>0
+ || pParse->db->mallocFailed!=0 );
if( pParse->db->mallocFailed ) {
clearSelect(pParse->db, pNew, pNew!=&standin);
pNew = 0;
@@ -169,7 +171,7 @@ void sqlite3SelectSetName(Select *p, const char *zName){
** Delete the given Select structure and all of its substructures.
*/
void sqlite3SelectDelete(sqlite3 *db, Select *p){
- if( p ) clearSelect(db, p, 1);
+ if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
}
/*
@@ -410,11 +412,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
pLeft = &pSrc->a[0];
pRight = &pLeft[1];
for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
- Table *pLeftTab = pLeft->pTab;
Table *pRightTab = pRight->pTab;
int isOuter;
- if( NEVER(pLeftTab==0 || pRightTab==0) ) continue;
+ if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
isOuter = (pRight->fg.jointype & JT_OUTER)!=0;
/* When the NATURAL keyword is present, add WHERE clause terms for
@@ -562,11 +563,11 @@ static void pushOntoSorter(
if( pParse->db->mallocFailed ) return;
pOp->p2 = nKey + nData;
pKI = pOp->p4.pKeyInfo;
- memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
+ memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
- testcase( pKI->nXField>2 );
+ testcase( pKI->nAllField > pKI->nKeyField+2 );
pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
- pKI->nXField-1);
+ pKI->nAllField-pKI->nKeyField-1);
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
@@ -664,16 +665,15 @@ static void codeDistinct(
** This routine generates the code for the inside of the inner loop
** of a SELECT.
**
-** If srcTab is negative, then the pEList expressions
+** 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 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(
Parse *pParse, /* The parser context */
Select *p, /* The complete select statement being coded */
- ExprList *pEList, /* List of values being extracted */
- int srcTab, /* Pull data from this table */
+ int srcTab, /* Pull data from this table if non-negative */
SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */
DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
SelectDest *pDest, /* How to dispose of the results */
@@ -697,7 +697,7 @@ static void selectInnerLoop(
int regOrig; /* Start of memory holding full result (or 0) */
assert( v );
- assert( pEList!=0 );
+ assert( p->pEList!=0 );
hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
if( pSort && pSort->pOrderBy==0 ) pSort = 0;
if( pSort==0 && !hasDistinct ){
@@ -707,7 +707,7 @@ static void selectInnerLoop(
/* Pull the requested columns.
*/
- nResultCol = pEList->nExpr;
+ nResultCol = p->pEList->nExpr;
if( pDest->iSdst==0 ){
if( pSort ){
@@ -730,7 +730,7 @@ static void selectInnerLoop(
if( srcTab>=0 ){
for(i=0; i<nResultCol; i++){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
- VdbeComment((v, "%s", pEList->a[i].zName));
+ VdbeComment((v, "%s", p->pEList->a[i].zName));
}
}else if( eDest!=SRT_Exists ){
/* If the destination is an EXISTS(...) expression, the actual
@@ -743,24 +743,25 @@ static void selectInnerLoop(
ecelFlags = 0;
}
if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab && eDest!=SRT_Table ){
- /* For each expression in pEList that is a copy of an expression in
+ /* 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
** expression within the sort-key that pushOntoSorter() will generate.
- ** This allows the pEList field to be omitted from the sorted record,
+ ** This allows the p->pEList field to be omitted from the sorted record,
** saving space and CPU cycles. */
ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF);
for(i=pSort->nOBSat; i<pSort->pOrderBy->nExpr; i++){
int j;
if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){
- pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat;
+ p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat;
}
}
regOrig = 0;
assert( eDest==SRT_Set || eDest==SRT_Mem
|| eDest==SRT_Coroutine || eDest==SRT_Output );
}
- nResultCol = sqlite3ExprCodeExprList(pParse,pEList,regResult,0,ecelFlags);
+ nResultCol = sqlite3ExprCodeExprList(pParse,p->pEList,regResult,
+ 0,ecelFlags);
}
/* If the DISTINCT keyword was present on the SELECT statement
@@ -792,7 +793,7 @@ static void selectInnerLoop(
iJump = sqlite3VdbeCurrentAddr(v) + nResultCol;
for(i=0; i<nResultCol; i++){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr);
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr);
if( i<nResultCol-1 ){
sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i);
VdbeCoverage(v);
@@ -1035,8 +1036,8 @@ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
if( p ){
p->aSortOrder = (u8*)&p->aColl[N+X];
- p->nField = (u16)N;
- p->nXField = (u16)X;
+ p->nKeyField = (u16)N;
+ p->nAllField = (u16)(N+X);
p->enc = ENC(db);
p->db = db;
p->nRef = 1;
@@ -1110,10 +1111,7 @@ static KeyInfo *keyInfoFromExprList(
if( pInfo ){
assert( sqlite3KeyInfoIsWriteable(pInfo) );
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
- CollSeq *pColl;
- pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- pInfo->aColl[i-iStart] = pColl;
+ pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr);
pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
}
}
@@ -1363,23 +1361,23 @@ static void generateSortTail(
** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used.
*/
#ifdef SQLITE_ENABLE_COLUMN_METADATA
-# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
+# define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E)
#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
-# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
+# define columnType(A,B,C,D,E) columnTypeImpl(A,B)
#endif
static const char *columnTypeImpl(
NameContext *pNC,
+#ifndef SQLITE_ENABLE_COLUMN_METADATA
+ Expr *pExpr
+#else
Expr *pExpr,
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
const char **pzOrigDb,
const char **pzOrigTab,
- const char **pzOrigCol,
+ const char **pzOrigCol
#endif
- u8 *pEstWidth
){
char const *zType = 0;
int j;
- u8 estWidth = 1;
#ifdef SQLITE_ENABLE_COLUMN_METADATA
char const *zOrigDb = 0;
char const *zOrigTab = 0;
@@ -1451,33 +1449,32 @@ static const char *columnTypeImpl(
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
- zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth);
+ zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol);
}
- }else if( pTab->pSchema ){
- /* A real table */
+ }else{
+ /* A real table or a CTE table */
assert( !pS );
- if( iCol<0 ) iCol = pTab->iPKey;
- assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
#ifdef SQLITE_ENABLE_COLUMN_METADATA
+ if( iCol<0 ) iCol = pTab->iPKey;
+ assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
zType = "INTEGER";
zOrigCol = "rowid";
}else{
zOrigCol = pTab->aCol[iCol].zName;
zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
- estWidth = pTab->aCol[iCol].szEst;
}
zOrigTab = pTab->zName;
- if( pNC->pParse ){
+ if( pNC->pParse && pTab->pSchema ){
int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName;
}
#else
+ assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
zType = "INTEGER";
}else{
zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
- estWidth = pTab->aCol[iCol].szEst;
}
#endif
}
@@ -1496,7 +1493,7 @@ static const char *columnTypeImpl(
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
- zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth);
+ zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
break;
}
#endif
@@ -1510,7 +1507,6 @@ static const char *columnTypeImpl(
*pzOrigCol = zOrigCol;
}
#endif
- if( pEstWidth ) *pEstWidth = estWidth;
return zType;
}
@@ -1537,7 +1533,7 @@ static void generateColumnTypes(
const char *zOrigDb = 0;
const char *zOrigTab = 0;
const char *zOrigCol = 0;
- zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0);
+ zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
/* The vdbe must make its own copy of the column-type and other
** column specific strings, in case the schema is reset before this
@@ -1547,7 +1543,7 @@ static void generateColumnTypes(
sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT);
sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT);
#else
- zType = columnType(&sNC, p, 0, 0, 0, 0);
+ zType = columnType(&sNC, p, 0, 0, 0);
#endif
sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
}
@@ -1589,9 +1585,9 @@ static Table *tableWithCursor(SrcList *pList, int iCursor){
** other words, the zSpan of the result expression.
**
** short=ON, full=OFF: (This is the default setting). If the result
-** refers directly to a table column, then the result
-** column name is just the table column name: COLUMN.
-** Otherwise use zSpan.
+** refers directly to a table column, then the
+** result column name is just the table column
+** name: COLUMN. Otherwise use zSpan.
**
** full=ON, short=ANY: If the result refers directly to a table column,
** then the result column name with the table name
@@ -1627,6 +1623,8 @@ static void generateColumnNames(
Expr *p = pEList->a[i].pExpr;
assert( p!=0 );
+ assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */
+ assert( p->op!=TK_COLUMN || p->pTab!=0 ); /* Covering idx not yet coded */
if( pEList->a[i].zName ){
/* An AS clause always takes first priority */
char *zName = pEList->a[i].zName;
@@ -1702,6 +1700,7 @@ int sqlite3ColumnsFromExprList(
nCol = pEList->nExpr;
aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
testcase( aCol==0 );
+ if( nCol>32767 ) nCol = 32767;
}else{
nCol = 0;
aCol = 0;
@@ -1721,7 +1720,9 @@ int sqlite3ColumnsFromExprList(
pColExpr = pColExpr->pRight;
assert( pColExpr!=0 );
}
- if( pColExpr->op==TK_COLUMN && pColExpr->pTab!=0 ){
+ if( (pColExpr->op==TK_COLUMN || pColExpr->op==TK_AGG_COLUMN)
+ && pColExpr->pTab!=0
+ ){
/* For columns use the column name name */
int iCol = pColExpr->iColumn;
Table *pTab = pColExpr->pTab;
@@ -1796,7 +1797,6 @@ void sqlite3SelectAddColumnTypeAndCollation(
int i;
Expr *p;
struct ExprList_item *a;
- u64 szAll = 0;
assert( pSelect!=0 );
assert( (pSelect->selFlags & SF_Resolved)!=0 );
@@ -1809,10 +1809,11 @@ void sqlite3SelectAddColumnTypeAndCollation(
const char *zType;
int n, m;
p = a[i].pExpr;
- zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
- szAll += pCol->szEst;
+ 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))>0 ){
+ if( zType ){
+ m = sqlite3Strlen30(zType);
n = sqlite3Strlen30(pCol->zName);
pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
if( pCol->zName ){
@@ -1826,7 +1827,7 @@ void sqlite3SelectAddColumnTypeAndCollation(
pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
}
}
- pTab->szTabRow = sqlite3LogEst(szAll*4);
+ pTab->szTabRow = 1; /* Any non-zero value works */
}
/*
@@ -1869,19 +1870,16 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
** Get a VDBE for the given parser context. Create a new one if necessary.
** If an error occurs, return NULL and leave a message in pParse.
*/
-static SQLITE_NOINLINE Vdbe *allocVdbe(Parse *pParse){
- Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
- if( v ) sqlite3VdbeAddOp2(v, OP_Init, 0, 1);
+Vdbe *sqlite3GetVdbe(Parse *pParse){
+ if( pParse->pVdbe ){
+ return pParse->pVdbe;
+ }
if( pParse->pToplevel==0
&& OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
){
pParse->okConstFactor = 1;
}
- return v;
-}
-Vdbe *sqlite3GetVdbe(Parse *pParse){
- Vdbe *v = pParse->pVdbe;
- return v ? v : allocVdbe(pParse);
+ return sqlite3VdbeCreate(pParse);
}
@@ -2154,7 +2152,7 @@ static void generateWithRecursiveQuery(
/* Output the single row in Current */
addrCont = sqlite3VdbeMakeLabel(v);
codeOffset(v, regOffset, addrCont);
- selectInnerLoop(pParse, p, p->pEList, iCurrent,
+ selectInnerLoop(pParse, p, iCurrent,
0, 0, pDest, addrCont, addrBreak);
if( regLimit ){
sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak);
@@ -2292,15 +2290,9 @@ static int multiSelect(
db = pParse->db;
pPrior = p->pPrior;
dest = *pDest;
- if( pPrior->pOrderBy ){
- sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
- selectOpName(p->op));
- rc = 1;
- goto multi_select_end;
- }
- if( pPrior->pLimit ){
- sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before",
- selectOpName(p->op));
+ 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;
}
@@ -2478,7 +2470,7 @@ static int multiSelect(
computeLimitRegisters(pParse, p, iBreak);
sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
iStart = sqlite3VdbeCurrentAddr(v);
- selectInnerLoop(pParse, p, p->pEList, unionTab,
+ selectInnerLoop(pParse, p, unionTab,
0, 0, &dest, iCont, iBreak);
sqlite3VdbeResolveLabel(v, iCont);
sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v);
@@ -2556,7 +2548,7 @@ static int multiSelect(
iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);
sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v);
sqlite3ReleaseTempReg(pParse, r1);
- selectInnerLoop(pParse, p, p->pEList, tab1,
+ selectInnerLoop(pParse, p, tab1,
0, 0, &dest, iCont, iBreak);
sqlite3VdbeResolveLabel(v, iCont);
sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v);
@@ -3216,7 +3208,9 @@ 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_FromJoin)
+ && pExpr->iRightJoinTable==pSubst->iTable
+ ){
pExpr->iRightJoinTable = pSubst->iNewTable;
}
if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){
@@ -3329,68 +3323,74 @@ static void substSelect(
** exist on the table t1, a complete scan of the data might be
** avoided.
**
-** Flattening is only attempted if all of the following are true:
+** Flattening is subject to the following constraints:
**
-** (1) The subquery and the outer query do not both use aggregates.
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** The subquery and the outer query cannot both be aggregates.
**
-** (2) The subquery is not an aggregate or (2a) the outer query is not a join
-** and (2b) the outer query does not use subqueries other than the one
-** FROM-clause subquery that is a candidate for flattening. (2b is
-** due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** (2) If the subquery is an aggregate then
+** (2a) the outer query must not be a join and
+** (2b) the outer query must not use subqueries
+** other than the one FROM-clause subquery that is a candidate
+** for flattening. (This is due to ticket [2f7170d73bf9abf80]
+** from 2015-02-09.)
**
-** (3) The subquery is not the right operand of a LEFT JOIN
-** or (a) the subquery is not itself a join and (b) the FROM clause
-** of the subquery does not contain a virtual table and (c) the
-** outer query is not an aggregate.
+** (3) If the subquery is the right operand of a LEFT JOIN then
+** (3a) the subquery may not be a join and
+** (3b) the FROM clause of the subquery may not contain a virtual
+** table and
+** (3c) the outer query may not be an aggregate.
**
-** (4) The subquery is not DISTINCT.
+** (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
** (4) has since been expanded to exclude all DISTINCT subqueries.
**
-** (6) The subquery does not use aggregates or the outer query is not
-** DISTINCT.
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** If the subquery is aggregate, the outer query may not be DISTINCT.
**
-** (7) The subquery has a FROM clause. TODO: For subqueries without
+** (7) The subquery must have a FROM clause. TODO: For subqueries without
** A FROM clause, consider adding a FROM clause with the special
** table sqlite_once that consists of a single row containing a
** single NULL.
**
-** (8) The subquery does not use LIMIT or the outer query is not a join.
+** (8) If the subquery uses LIMIT then the outer query may not be a join.
**
-** (9) The subquery does not use LIMIT or the outer query does not use
-** aggregates.
+** (9) If the subquery uses LIMIT then the outer query may not be aggregate.
**
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
** accidently carried the comment forward until 2014-09-15. Original
-** text: "The subquery does not use aggregates or the outer query
-** does not use LIMIT."
+** constraint: "If the subquery is aggregate then the outer query
+** may not use LIMIT."
**
-** (11) The subquery and the outer query do not both have ORDER BY clauses.
+** (11) The subquery and the outer query may not both have ORDER BY clauses.
**
** (**) Not implemented. Subsumed into restriction (3). Was previously
** a separate restriction deriving from ticket #350.
**
-** (13) The subquery and outer query do not both use LIMIT.
+** (13) The subquery and outer query may not both use LIMIT.
**
-** (14) The subquery does not use OFFSET.
+** (14) The subquery may not use OFFSET.
**
-** (15) The outer query is not part of a compound select or the
-** subquery does not have a LIMIT clause.
+** (15) If the outer query is part of a compound select, then the
+** subquery may not use LIMIT.
** (See ticket #2339 and ticket [02a8e81d44]).
**
-** (16) The outer query is not an aggregate or the subquery does
-** not contain ORDER BY. (Ticket #2942) This used to not matter
+** (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.
**
-** (17) The sub-query is not a compound select, or it is a UNION ALL
-** compound clause made up entirely of non-aggregate queries, and
-** the parent query:
-**
-** * is not itself part of a compound select,
-** * is not an aggregate or DISTINCT query, and
-** * is not a join
+** (17) If the subquery is a compound select, then
+** (17a) all compound operators must be a UNION ALL, and
+** (17b) no terms within the subquery compound may be aggregate
+** or DISTINCT, and
+** (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.
**
** The parent and sub-query may contain WHERE clauses. Subject to
** rules (11), (13) and (14), they may also contain ORDER BY,
@@ -3406,29 +3406,32 @@ 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
+** ORDER BY clause of the parent must be simple references to
** columns of the sub-query.
**
-** (19) The subquery does not use LIMIT or the outer query does not
+** (19) If the subquery uses LIMIT then the outer query may not
** have a WHERE clause.
**
-** (20) If the sub-query is a compound select, then it must not use
-** an ORDER BY clause. Ticket #3773. We could relax this constraint
-** somewhat by saying that the terms of the ORDER BY clause must
-** appear as unmodified result columns in the outer query. But we
-** have other optimizations in mind to deal with that case.
+** (**) Subsumed into (17d3). Was: If the sub-query is a compound select,
+** then it must not use an ORDER BY clause - Ticket #3773. Because
+** of (17d3), then only way to have a compound subquery is if it is
+** the only term in the FROM clause of the outer query. But if the
+** only term in the FROM clause has an ORDER BY, then it will be
+** implemented as a co-routine and the flattener will never be called.
**
-** (21) The subquery does not use LIMIT or the outer query is not
+** (21) If the subquery uses LIMIT then the outer query may not be
** DISTINCT. (See ticket [752e1646fc]).
**
-** (22) The subquery is not a recursive CTE.
+** (22) The subquery may not be a recursive CTE.
**
-** (23) The parent is not a recursive CTE, or the sub-query is not a
-** compound query. This restriction is because transforming the
+** (**) 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
** parent to a compound query confuses the code that handles
** recursive queries in multiSelect().
**
-** (24) The subquery is not an aggregate that uses the built-in min() or
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** 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.)
@@ -3436,7 +3439,7 @@ static void substSelect(
**
** 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
-** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
+** uses aggregates.
**
** If flattening is not attempted, this routine is a no-op and returns 0.
** If flattening is attempted this routine returns 1.
@@ -3448,8 +3451,7 @@ static int flattenSubquery(
Parse *pParse, /* Parsing context */
Select *p, /* The parent or outer SELECT statement */
int iFrom, /* Index in p->pSrc->a[] of the inner subquery */
- int isAgg, /* True if outer SELECT uses aggregate functions */
- int subqueryIsAgg /* True if the subquery uses aggregate functions */
+ int isAgg /* True if outer SELECT uses aggregate functions */
){
const char *zSavedAuthContext = pParse->zAuthContext;
Select *pParent; /* Current UNION ALL term of the other query */
@@ -3469,7 +3471,7 @@ static int flattenSubquery(
/* Check to see if flattening is permitted. Return 0 if not.
*/
assert( p!=0 );
- assert( p->pPrior==0 ); /* Unable to flatten compound queries */
+ assert( p->pPrior==0 );
if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
pSrc = p->pSrc;
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
@@ -3477,16 +3479,6 @@ static int flattenSubquery(
iParent = pSubitem->iCursor;
pSub = pSubitem->pSelect;
assert( pSub!=0 );
- if( subqueryIsAgg ){
- if( isAgg ) return 0; /* Restriction (1) */
- if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */
- if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery))
- || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0
- || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0
- ){
- return 0; /* Restriction (2b) */
- }
- }
pSubSrc = pSub->pSrc;
assert( pSubSrc );
@@ -3501,13 +3493,10 @@ static int flattenSubquery(
return 0; /* Restriction (15) */
}
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
- if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */
+ if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (4) */
if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){
return 0; /* Restrictions (8)(9) */
}
- if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){
- return 0; /* Restriction (6) */
- }
if( p->pOrderBy && pSub->pOrderBy ){
return 0; /* Restriction (11) */
}
@@ -3516,18 +3505,14 @@ static int flattenSubquery(
if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
return 0; /* Restriction (21) */
}
- testcase( pSub->selFlags & SF_Recursive );
- testcase( pSub->selFlags & SF_MinMaxAgg );
- if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){
- return 0; /* Restrictions (22) and (24) */
- }
- if( (p->selFlags & SF_Recursive) && pSub->pPrior ){
- return 0; /* Restriction (23) */
+ if( pSub->selFlags & (SF_Recursive) ){
+ return 0; /* Restrictions (22) */
}
/*
** If the subquery is the right operand of a LEFT JOIN, then the
- ** subquery may not be a join itself. Example of why this is not allowed:
+ ** subquery may not be a join itself (3a). Example of why this is not
+ ** allowed:
**
** t1 LEFT OUTER JOIN (t2 JOIN t3)
**
@@ -3538,54 +3523,53 @@ 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. 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.
+ ** 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 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){
- return 0; /* Restriction (3) */
+ /* (3a) (3c) (3b) */
+ return 0;
}
}
#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. */
+ ** 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;
}
#endif
- /* Restriction 17: If the sub-query is a compound SELECT, then it must
+ /* 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
** that make up the compound SELECT are allowed to be aggregate or distinct
** queries.
*/
if( pSub->pPrior ){
- if( pSub->pOrderBy ){
- return 0; /* Restriction 20 */
- }
if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){
- return 0;
+ return 0; /* (17d1), (17d2), or (17d3) */
}
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->pEList->nExpr==pSub1->pEList->nExpr );
- if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0
- || (pSub1->pPrior && pSub1->op!=TK_ALL)
- || pSub1->pSrc->nSrc<1
+ if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */
+ || (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */
+ || pSub1->pSrc->nSrc<1 /* (17c) */
){
return 0;
}
testcase( pSub1->pSrc->nSrc>1 );
}
- /* Restriction 18. */
+ /* Restriction (18). */
if( p->pOrderBy ){
int ii;
for(ii=0; ii<p->pOrderBy->nExpr; ii++){
@@ -3594,6 +3578,23 @@ static int flattenSubquery(
}
}
+ /* 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 );
+
+ /* Ex-restriction (20):
+ ** A compound subquery must be the only term in the FROM clause of the
+ ** outer query by restriction (17d3). But if that term also has an
+ ** ORDER BY clause, then the subquery will be implemented by co-routine
+ ** and so the flattener will never be invoked. Hence, it is not possible
+ ** for the subquery to be a compound and have an ORDER BY clause.
+ */
+ assert( pSub->pPrior==0 || pSub->pOrderBy==0 );
+
/***** If we reach this point, flattening is permitted. *****/
SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n",
pSub->zSelName, pSub, iFrom));
@@ -3814,18 +3815,7 @@ static int flattenSubquery(
if( isLeftJoin>0 ){
setJoinExpr(pWhere, iNewParent);
}
- if( subqueryIsAgg ){
- assert( pParent->pHaving==0 );
- pParent->pHaving = pParent->pWhere;
- pParent->pWhere = pWhere;
- pParent->pHaving = sqlite3ExprAnd(db,
- sqlite3ExprDup(db, pSub->pHaving, 0), pParent->pHaving
- );
- assert( pParent->pGroupBy==0 );
- pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
- }else{
- pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
- }
+ pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
if( db->mallocFailed==0 ){
SubstContext x;
x.pParse = pParse;
@@ -3888,9 +3878,13 @@ static int flattenSubquery(
**
** Do not attempt this optimization if:
**
-** (1) The inner query is an aggregate. (In that case, we'd really want
-** to copy the outer WHERE-clause terms onto the HAVING clause of the
-** inner query. But they probably won't help there so do not bother.)
+** (1) (** This restriction was removed on 2017-09-29. We used to
+** disallow this optimization for aggregate subqueries, but now
+** it is allowed by putting the extra terms on the HAVING clause.
+** The added HAVING clause is pointless if the subquery lacks
+** a GROUP BY clause. But such a HAVING clause is also harmless
+** so there does not appear to be any reason to add extra logic
+** to suppress it. **)
**
** (2) The inner query is the recursive part of a common table expression.
**
@@ -3915,16 +3909,22 @@ static int pushDownWhereTerms(
){
Expr *pNew;
int nChng = 0;
- Select *pX; /* For looping over compound SELECTs in pSubq */
if( pWhere==0 ) return 0;
- for(pX=pSubq; pX; pX=pX->pPrior){
- if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
- testcase( pX->selFlags & SF_Aggregate );
- testcase( pX->selFlags & SF_Recursive );
- testcase( pX!=pSubq );
- return 0; /* restrictions (1) and (2) */
+ if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */
+
+#ifdef SQLITE_DEBUG
+ /* Only the first term of a compound can have a WITH clause. But make
+ ** sure no other terms are marked SF_Recursive in case something changes
+ ** in the future.
+ */
+ {
+ Select *pX;
+ for(pX=pSubq; pX; pX=pX->pPrior){
+ assert( (pX->selFlags & (SF_Recursive))==0 );
}
}
+#endif
+
if( pSubq->pLimit!=0 ){
return 0; /* restriction (3) */
}
@@ -3932,7 +3932,7 @@ static int pushDownWhereTerms(
nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor);
pWhere = pWhere->pLeft;
}
- if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
+ if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction (5) */
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
nChng++;
while( pSubq ){
@@ -3944,7 +3944,11 @@ static int pushDownWhereTerms(
x.isLeftJoin = 0;
x.pEList = pSubq->pEList;
pNew = substExpr(&x, pNew);
- pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
+ if( pSubq->selFlags & SF_Aggregate ){
+ pSubq->pHaving = sqlite3ExprAnd(pParse->db, pSubq->pHaving, pNew);
+ }else{
+ pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
+ }
pSubq = pSubq->pPrior;
}
}
@@ -4272,7 +4276,8 @@ static int withExpand(
);
return SQLITE_ERROR;
}
- assert( pTab->nTabRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
+ assert( pTab->nTabRef==1 ||
+ ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
pCte->zCteErr = "circular reference: %s";
pSavedWith = pParse->pWith;
@@ -4329,7 +4334,7 @@ static int withExpand(
*/
static void selectPopWith(Walker *pWalker, Select *p){
Parse *pParse = pWalker->pParse;
- if( pParse->pWith && p->pPrior==0 ){
+ if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){
With *pWith = findRightmost(p)->pWith;
if( pWith!=0 ){
assert( pParse->pWith==pWith );
@@ -4384,7 +4389,7 @@ static int selectExpander(Walker *pWalker, Select *p){
}
pTabList = p->pSrc;
pEList = p->pEList;
- if( p->pWith ){
+ if( OK_IF_ALWAYS_TRUE(p->pWith) ){
sqlite3WithPush(pParse, p->pWith, 0);
}
@@ -4416,7 +4421,11 @@ static int selectExpander(Walker *pWalker, Select *p){
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return WRC_Abort;
pTab->nTabRef = 1;
- pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
+ if( pFrom->zAlias ){
+ pTab->zName = sqlite3DbStrDup(db, pFrom->zAlias);
+ }else{
+ pTab->zName = sqlite3MPrintf(db, "subquery_%p", (void*)pTab);
+ }
while( pSel->pPrior ){ pSel = pSel->pPrior; }
sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
pTab->iPKey = -1;
@@ -4626,12 +4635,10 @@ static int selectExpander(Walker *pWalker, Select *p){
sqlite3ExprListDelete(db, pEList);
p->pEList = pNew;
}
-#if SQLITE_MAX_COLUMN
if( p->pEList && p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many columns in result set");
return WRC_Abort;
}
-#endif
return WRC_Continue;
}
@@ -4685,7 +4692,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
Walker w;
w.xExprCallback = sqlite3ExprWalkNoop;
w.pParse = pParse;
- if( pParse->hasCompound ){
+ if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){
w.xSelectCallback = convertCompoundSelectToSubquery;
w.xSelectCallback2 = 0;
sqlite3WalkSelect(&w, pSelect);
@@ -4773,15 +4780,13 @@ void sqlite3SelectPrep(
Select *p, /* The SELECT statement being coded. */
NameContext *pOuterNC /* Name context for container */
){
- sqlite3 *db;
- if( NEVER(p==0) ) return;
- db = pParse->db;
- if( db->mallocFailed ) return;
+ assert( p!=0 || pParse->db->mallocFailed );
+ if( pParse->db->mallocFailed ) return;
if( p->selFlags & SF_HasTypeInfo ) return;
sqlite3SelectExpand(pParse, p);
- if( pParse->nErr || db->mallocFailed ) return;
+ if( pParse->nErr || pParse->db->mallocFailed ) return;
sqlite3ResolveSelectNames(pParse, p, pOuterNC);
- if( pParse->nErr || db->mallocFailed ) return;
+ if( pParse->nErr || pParse->db->mallocFailed ) return;
sqlite3SelectAddTypeInfo(pParse, p);
}
@@ -5076,24 +5081,24 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
Expr *pExpr;
Expr *pCount;
sqlite3 *db;
- if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate query */
+ if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
pExpr = p->pEList->a[0].pExpr;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */
- if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Must be count() */
+ if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
- if( p->pSrc->nSrc!=1 ) return 0; /* One table in the FROM clause */
+ if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
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 subquery */
+ if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */
do{
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
if( pSub->pWhere ) return 0; /* No WHERE clause */
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
- pSub = pSub->pPrior; /* Repeat over compound terms */
+ pSub = pSub->pPrior; /* Repeat over compound */
}while( pSub );
- /* If we reach this point, that means it is OK to perform the transformation */
+ /* If we reach this point then it is OK to perform the transformation */
db = pParse->db;
pCount = pExpr;
@@ -5225,7 +5230,6 @@ int sqlite3Select(
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
struct SrcList_item *pItem = &pTabList->a[i];
Select *pSub = pItem->pSelect;
- int isAggSub;
Table *pTab = pItem->pTab;
if( pSub==0 ) continue;
@@ -5237,13 +5241,36 @@ int sqlite3Select(
goto select_end;
}
- isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
- if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
+ /* Do not try to flatten an aggregate subquery.
+ **
+ ** Flattening an aggregate subquery is only possible if the outer query
+ ** is not a join. But if the outer query is not a join, then the subquery
+ ** will be implemented as a co-routine and there is no advantage to
+ ** flattening in that case.
+ */
+ if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
+ assert( pSub->pGroupBy==0 );
+
+ /* If the subquery contains an ORDER BY clause and if
+ ** it will be implemented as a co-routine, then do not flatten. This
+ ** restriction allows SQL constructs like this:
+ **
+ ** SELECT expensive_function(x)
+ ** FROM (SELECT x FROM tab ORDER BY y LIMIT 10);
+ **
+ ** The expensive_function() is only computed on the 10 rows that
+ ** are output, rather than every row of the table.
+ */
+ if( pSub->pOrderBy!=0
+ && i==0
+ && (pTabList->nSrc==1
+ || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0)
+ ){
+ continue;
+ }
+
+ if( flattenSubquery(pParse, p, i, isAgg) ){
/* This subquery can be absorbed into its parent. */
- if( isAggSub ){
- isAgg = 1;
- p->selFlags |= SF_Aggregate;
- }
i = -1;
}
pTabList = p->pSrc;
@@ -5282,10 +5309,14 @@ int sqlite3Select(
struct SrcList_item *pItem = &pTabList->a[i];
SelectDest dest;
Select *pSub;
+#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+ const char *zSavedAuthContext;
+#endif
- /* Issue SQLITE_READ authorizations with a fake column name for any tables that
- ** are referenced but from which no values are extracted. Examples of where these
- ** kinds of null SQLITE_READ authorizations would occur:
+ /* Issue SQLITE_READ authorizations with a fake column name for any
+ ** tables that are referenced but from which no values are extracted.
+ ** Examples of where these kinds of null SQLITE_READ authorizations
+ ** would occur:
**
** SELECT count(*) FROM t1; -- SQLITE_READ t1.""
** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2.""
@@ -5293,10 +5324,10 @@ int sqlite3Select(
** The fake column name is an empty string. It is possible for a table to
** have a column named by the empty string, in which case there is no way to
** distinguish between an unreferenced table and an actual reference to the
- ** "" column. The original design was for the fake column name to be a NULL,
+ ** "" column. The original design was for the fake column name to be a NULL,
** which would be unambiguous. But legacy authorization callbacks might
- ** assume the column name is non-NULL and segfault. The use of an empty string
- ** for the fake column name seems safer.
+ ** assume the column name is non-NULL and segfault. The use of an empty
+ ** string for the fake column name seems safer.
*/
if( pItem->colUsed==0 ){
sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
@@ -5348,16 +5379,14 @@ int sqlite3Select(
#endif
}
+ zSavedAuthContext = pParse->zAuthContext;
+ pParse->zAuthContext = pItem->zName;
+
/* Generate code to implement the subquery
**
- ** The subquery is implemented as a co-routine if all of these are true:
- ** (1) The subquery is guaranteed to be the outer loop (so that it
- ** does not need to be computed more than once)
- ** (2) The ALL keyword after SELECT is omitted. (Applications are
- ** allowed to say "SELECT ALL" instead of just "SELECT" to disable
- ** the use of co-routines.)
- ** (3) Co-routines are not disabled using sqlite3_test_control()
- ** with SQLITE_TESTCTRL_OPTIMIZATIONS.
+ ** 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?
@@ -5365,13 +5394,12 @@ int sqlite3Select(
if( i==0
&& (pTabList->nSrc==1
|| (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
- && (p->selFlags & SF_All)==0 /* (2) */
- && OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */
){
/* 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));
@@ -5429,6 +5457,7 @@ int sqlite3Select(
}
if( db->mallocFailed ) goto select_end;
pParse->nHeight -= sqlite3SelectExprHeight(p);
+ pParse->zAuthContext = zSavedAuthContext;
#endif
}
@@ -5576,7 +5605,8 @@ int sqlite3Select(
}
/* Use the standard inner loop. */
- selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
+ assert( p->pEList==pEList );
+ selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest,
sqlite3WhereContinueLabel(pWInfo),
sqlite3WhereBreakLabel(pWInfo));
@@ -5879,7 +5909,7 @@ int sqlite3Select(
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
finalizeAggFunctions(pParse, &sAggInfo);
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
- selectInnerLoop(pParse, p, p->pEList, -1, &sSort,
+ selectInnerLoop(pParse, p, -1, &sSort,
&sDistinct, pDest,
addrOutputRow+1, addrSetAbort);
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
@@ -6023,7 +6053,7 @@ int sqlite3Select(
sSort.pOrderBy = 0;
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
- selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
+ selectInnerLoop(pParse, p, -1, 0, 0,
pDest, addrEnd, addrEnd);
sqlite3ExprListDelete(db, pDel);
}
diff --git a/third_party/sqlite/src/src/shell.c b/third_party/sqlite/src/src/shell.c
deleted file mode 100644
index 33f41f6..0000000
--- a/third_party/sqlite/src/src/shell.c
+++ /dev/null
@@ -1,8409 +0,0 @@
-/* DO NOT EDIT!
-** This file is automatically generated by the script in the canonical
-** SQLite source tree at tool/mkshellc.tcl. That script combines source
-** code from various constituent source files of SQLite into this single
-** "shell.c" file used to implement the SQLite command-line shell.
-**
-** Most of the code found below comes from the "src/shell.c.in" file in
-** the canonical SQLite source tree. That main file contains "INCLUDE"
-** lines that specify other files in the canonical source tree that are
-** inserted to getnerate this complete program source file.
-**
-** The code from multiple files is combined into this single "shell.c"
-** source file to help make the command-line program easier to compile.
-**
-** To modify this program, get a copy of the canonical SQLite source tree,
-** edit the src/shell.c.in" and/or some of the other files that are included
-** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script.
-*/
-/*
-** 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 file contains code to implement the "sqlite" command line
-** utility for accessing SQLite databases.
-*/
-#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
-/* This needs to come before any includes for MSVC compiler */
-#define _CRT_SECURE_NO_WARNINGS
-#endif
-
-/*
-** Warning pragmas copied from msvc.h in the core.
-*/
-#if defined(_MSC_VER)
-#pragma warning(disable : 4054)
-#pragma warning(disable : 4055)
-#pragma warning(disable : 4100)
-#pragma warning(disable : 4127)
-#pragma warning(disable : 4130)
-#pragma warning(disable : 4152)
-#pragma warning(disable : 4189)
-#pragma warning(disable : 4206)
-#pragma warning(disable : 4210)
-#pragma warning(disable : 4232)
-#pragma warning(disable : 4244)
-#pragma warning(disable : 4305)
-#pragma warning(disable : 4306)
-#pragma warning(disable : 4702)
-#pragma warning(disable : 4706)
-#endif /* defined(_MSC_VER) */
-
-/*
-** No support for loadable extensions in VxWorks.
-*/
-#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION
-# define SQLITE_OMIT_LOAD_EXTENSION 1
-#endif
-
-/*
-** Enable large-file support for fopen() and friends on unix.
-*/
-#ifndef SQLITE_DISABLE_LFS
-# define _LARGE_FILE 1
-# ifndef _FILE_OFFSET_BITS
-# define _FILE_OFFSET_BITS 64
-# endif
-# define _LARGEFILE_SOURCE 1
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include "sqlite3.h"
-#if SQLITE_USER_AUTHENTICATION
-# include "sqlite3userauth.h"
-#endif
-#include <ctype.h>
-#include <stdarg.h>
-
-#if !defined(_WIN32) && !defined(WIN32)
-# include <signal.h>
-# if !defined(__RTP__) && !defined(_WRS_KERNEL)
-# include <pwd.h>
-# endif
-# include <unistd.h>
-# include <sys/types.h>
-#endif
-
-#if HAVE_READLINE
-# include <readline/readline.h>
-# include <readline/history.h>
-#endif
-
-#if HAVE_EDITLINE
-# include <editline/readline.h>
-#endif
-
-#if HAVE_EDITLINE || HAVE_READLINE
-
-# define shell_add_history(X) add_history(X)
-# define shell_read_history(X) read_history(X)
-# define shell_write_history(X) write_history(X)
-# define shell_stifle_history(X) stifle_history(X)
-# define shell_readline(X) readline(X)
-
-#elif HAVE_LINENOISE
-
-# include "linenoise.h"
-# define shell_add_history(X) linenoiseHistoryAdd(X)
-# define shell_read_history(X) linenoiseHistoryLoad(X)
-# define shell_write_history(X) linenoiseHistorySave(X)
-# define shell_stifle_history(X) linenoiseHistorySetMaxLen(X)
-# define shell_readline(X) linenoise(X)
-
-#else
-
-# define shell_read_history(X)
-# define shell_write_history(X)
-# define shell_stifle_history(X)
-
-# define SHELL_USE_LOCAL_GETLINE 1
-#endif
-
-
-#if defined(_WIN32) || defined(WIN32)
-# include <io.h>
-# include <fcntl.h>
-# define isatty(h) _isatty(h)
-# ifndef access
-# define access(f,m) _access((f),(m))
-# endif
-# undef popen
-# define popen _popen
-# undef pclose
-# define pclose _pclose
-#else
- /* Make sure isatty() has a prototype. */
- extern int isatty(int);
-
-# if !defined(__RTP__) && !defined(_WRS_KERNEL)
- /* popen and pclose are not C89 functions and so are
- ** sometimes omitted from the <stdio.h> header */
- extern FILE *popen(const char*,const char*);
- extern int pclose(FILE*);
-# else
-# define SQLITE_OMIT_POPEN 1
-# endif
-#endif
-
-#if defined(_WIN32_WCE)
-/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
- * thus we always assume that we have a console. That can be
- * overridden with the -batch command line option.
- */
-#define isatty(x) 1
-#endif
-
-/* ctype macros that work with signed characters */
-#define IsSpace(X) isspace((unsigned char)X)
-#define IsDigit(X) isdigit((unsigned char)X)
-#define ToLower(X) (char)tolower((unsigned char)X)
-
-#if defined(_WIN32) || defined(WIN32)
-#include <windows.h>
-
-/* string conversion routines only needed on Win32 */
-extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR);
-extern char *sqlite3_win32_mbcs_to_utf8_v2(const char *, int);
-extern char *sqlite3_win32_utf8_to_mbcs_v2(const char *, int);
-extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
-#endif
-
-/* On Windows, we normally run with output mode of TEXT so that \n characters
-** are automatically translated into \r\n. However, this behavior needs
-** to be disabled in some cases (ex: when generating CSV output and when
-** rendering quoted strings that contain \n characters). The following
-** routines take care of that.
-*/
-#if defined(_WIN32) || defined(WIN32)
-static void setBinaryMode(FILE *file, int isOutput){
- if( isOutput ) fflush(file);
- _setmode(_fileno(file), _O_BINARY);
-}
-static void setTextMode(FILE *file, int isOutput){
- if( isOutput ) fflush(file);
- _setmode(_fileno(file), _O_TEXT);
-}
-#else
-# define setBinaryMode(X,Y)
-# define setTextMode(X,Y)
-#endif
-
-
-/* True if the timer is enabled */
-static int enableTimer = 0;
-
-/* Return the current wall-clock time */
-static sqlite3_int64 timeOfDay(void){
- static sqlite3_vfs *clockVfs = 0;
- sqlite3_int64 t;
- if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
- if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
- clockVfs->xCurrentTimeInt64(clockVfs, &t);
- }else{
- double r;
- clockVfs->xCurrentTime(clockVfs, &r);
- t = (sqlite3_int64)(r*86400000.0);
- }
- return t;
-}
-
-#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
-#include <sys/time.h>
-#include <sys/resource.h>
-
-/* VxWorks does not support getrusage() as far as we can determine */
-#if defined(_WRS_KERNEL) || defined(__RTP__)
-struct rusage {
- struct timeval ru_utime; /* user CPU time used */
- struct timeval ru_stime; /* system CPU time used */
-};
-#define getrusage(A,B) memset(B,0,sizeof(*B))
-#endif
-
-/* Saved resource information for the beginning of an operation */
-static struct rusage sBegin; /* CPU time at start */
-static sqlite3_int64 iBegin; /* Wall-clock time at start */
-
-/*
-** Begin timing an operation
-*/
-static void beginTimer(void){
- if( enableTimer ){
- getrusage(RUSAGE_SELF, &sBegin);
- iBegin = timeOfDay();
- }
-}
-
-/* Return the difference of two time_structs in seconds */
-static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
- return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
- (double)(pEnd->tv_sec - pStart->tv_sec);
-}
-
-/*
-** Print the timing results.
-*/
-static void endTimer(void){
- if( enableTimer ){
- sqlite3_int64 iEnd = timeOfDay();
- struct rusage sEnd;
- getrusage(RUSAGE_SELF, &sEnd);
- printf("Run Time: real %.3f user %f sys %f\n",
- (iEnd - iBegin)*0.001,
- timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
- timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
- }
-}
-
-#define BEGIN_TIMER beginTimer()
-#define END_TIMER endTimer()
-#define HAS_TIMER 1
-
-#elif (defined(_WIN32) || defined(WIN32))
-
-/* Saved resource information for the beginning of an operation */
-static HANDLE hProcess;
-static FILETIME ftKernelBegin;
-static FILETIME ftUserBegin;
-static sqlite3_int64 ftWallBegin;
-typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME,
- LPFILETIME, LPFILETIME);
-static GETPROCTIMES getProcessTimesAddr = NULL;
-
-/*
-** Check to see if we have timer support. Return 1 if necessary
-** support found (or found previously).
-*/
-static int hasTimer(void){
- if( getProcessTimesAddr ){
- return 1;
- } else {
- /* GetProcessTimes() isn't supported in WIN95 and some other Windows
- ** versions. See if the version we are running on has it, and if it
- ** does, save off a pointer to it and the current process handle.
- */
- hProcess = GetCurrentProcess();
- if( hProcess ){
- HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
- if( NULL != hinstLib ){
- getProcessTimesAddr =
- (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
- if( NULL != getProcessTimesAddr ){
- return 1;
- }
- FreeLibrary(hinstLib);
- }
- }
- }
- return 0;
-}
-
-/*
-** Begin timing an operation
-*/
-static void beginTimer(void){
- if( enableTimer && getProcessTimesAddr ){
- FILETIME ftCreation, ftExit;
- getProcessTimesAddr(hProcess,&ftCreation,&ftExit,
- &ftKernelBegin,&ftUserBegin);
- ftWallBegin = timeOfDay();
- }
-}
-
-/* Return the difference of two FILETIME structs in seconds */
-static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
- sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
- sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
- return (double) ((i64End - i64Start) / 10000000.0);
-}
-
-/*
-** Print the timing results.
-*/
-static void endTimer(void){
- if( enableTimer && getProcessTimesAddr){
- FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
- sqlite3_int64 ftWallEnd = timeOfDay();
- getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
- printf("Run Time: real %.3f user %f sys %f\n",
- (ftWallEnd - ftWallBegin)*0.001,
- timeDiff(&ftUserBegin, &ftUserEnd),
- timeDiff(&ftKernelBegin, &ftKernelEnd));
- }
-}
-
-#define BEGIN_TIMER beginTimer()
-#define END_TIMER endTimer()
-#define HAS_TIMER hasTimer()
-
-#else
-#define BEGIN_TIMER
-#define END_TIMER
-#define HAS_TIMER 0
-#endif
-
-/*
-** Used to prevent warnings about unused parameters
-*/
-#define UNUSED_PARAMETER(x) (void)(x)
-
-/*
-** If the following flag is set, then command execution stops
-** at an error if we are not interactive.
-*/
-static int bail_on_error = 0;
-
-/*
-** Threat stdin as an interactive input if the following variable
-** is true. Otherwise, assume stdin is connected to a file or pipe.
-*/
-static int stdin_is_interactive = 1;
-
-/*
-** On Windows systems we have to know if standard output is a console
-** in order to translate UTF-8 into MBCS. The following variable is
-** true if translation is required.
-*/
-static int stdout_is_console = 1;
-
-/*
-** The following is the open SQLite database. We make a pointer
-** to this database a static variable so that it can be accessed
-** by the SIGINT handler to interrupt database processing.
-*/
-static sqlite3 *globalDb = 0;
-
-/*
-** True if an interrupt (Control-C) has been received.
-*/
-static volatile int seenInterrupt = 0;
-
-/*
-** This is the name of our program. It is set in main(), used
-** in a number of other places, mostly for error messages.
-*/
-static char *Argv0;
-
-/*
-** Prompt strings. Initialized in main. Settable with
-** .prompt main continue
-*/
-static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
-static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
-
-/*
-** Render output like fprintf(). Except, if the output is going to the
-** console and if this is running on a Windows machine, translate the
-** output from UTF-8 into MBCS.
-*/
-#if defined(_WIN32) || defined(WIN32)
-void utf8_printf(FILE *out, const char *zFormat, ...){
- va_list ap;
- va_start(ap, zFormat);
- if( stdout_is_console && (out==stdout || out==stderr) ){
- char *z1 = sqlite3_vmprintf(zFormat, ap);
- char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
- sqlite3_free(z1);
- fputs(z2, out);
- sqlite3_free(z2);
- }else{
- vfprintf(out, zFormat, ap);
- }
- va_end(ap);
-}
-#elif !defined(utf8_printf)
-# define utf8_printf fprintf
-#endif
-
-/*
-** Render output like fprintf(). This should not be used on anything that
-** includes string formatting (e.g. "%s").
-*/
-#if !defined(raw_printf)
-# define raw_printf fprintf
-#endif
-
-/*
-** Write I/O traces to the following stream.
-*/
-#ifdef SQLITE_ENABLE_IOTRACE
-static FILE *iotrace = 0;
-#endif
-
-/*
-** This routine works like printf in that its first argument is a
-** format string and subsequent arguments are values to be substituted
-** in place of % fields. The result of formatting this string
-** is written to iotrace.
-*/
-#ifdef SQLITE_ENABLE_IOTRACE
-static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
- va_list ap;
- char *z;
- if( iotrace==0 ) return;
- va_start(ap, zFormat);
- z = sqlite3_vmprintf(zFormat, ap);
- va_end(ap);
- utf8_printf(iotrace, "%s", z);
- sqlite3_free(z);
-}
-#endif
-
-/*
-** Output string zUtf to stream pOut as w characters. If w is negative,
-** then right-justify the text. W is the width in UTF-8 characters, not
-** in bytes. This is different from the %*.*s specification in printf
-** since with %*.*s the width is measured in bytes, not characters.
-*/
-static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
- int i;
- int n;
- int aw = w<0 ? -w : w;
- char zBuf[1000];
- if( aw>(int)sizeof(zBuf)/3 ) aw = (int)sizeof(zBuf)/3;
- for(i=n=0; zUtf[i]; i++){
- if( (zUtf[i]&0xc0)!=0x80 ){
- n++;
- if( n==aw ){
- do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
- break;
- }
- }
- }
- if( n>=aw ){
- utf8_printf(pOut, "%.*s", i, zUtf);
- }else if( w<0 ){
- utf8_printf(pOut, "%*s%s", aw-n, "", zUtf);
- }else{
- utf8_printf(pOut, "%s%*s", zUtf, aw-n, "");
- }
-}
-
-
-/*
-** Determines if a string is a number of not.
-*/
-static int isNumber(const char *z, int *realnum){
- if( *z=='-' || *z=='+' ) z++;
- if( !IsDigit(*z) ){
- return 0;
- }
- z++;
- if( realnum ) *realnum = 0;
- while( IsDigit(*z) ){ z++; }
- if( *z=='.' ){
- z++;
- if( !IsDigit(*z) ) return 0;
- while( IsDigit(*z) ){ z++; }
- if( realnum ) *realnum = 1;
- }
- if( *z=='e' || *z=='E' ){
- z++;
- if( *z=='+' || *z=='-' ) z++;
- if( !IsDigit(*z) ) return 0;
- while( IsDigit(*z) ){ z++; }
- if( realnum ) *realnum = 1;
- }
- return *z==0;
-}
-
-/*
-** Compute a string length that is limited to what can be stored in
-** lower 30 bits of a 32-bit signed integer.
-*/
-static int strlen30(const char *z){
- const char *z2 = z;
- while( *z2 ){ z2++; }
- return 0x3fffffff & (int)(z2 - z);
-}
-
-/*
-** Return the length of a string in characters. Multibyte UTF8 characters
-** count as a single character.
-*/
-static int strlenChar(const char *z){
- int n = 0;
- while( *z ){
- if( (0xc0&*(z++))!=0x80 ) n++;
- }
- return n;
-}
-
-/*
-** This routine reads a line of text from FILE in, stores
-** the text in memory obtained from malloc() and returns a pointer
-** to the text. NULL is returned at end of file, or if malloc()
-** fails.
-**
-** If zLine is not NULL then it is a malloced buffer returned from
-** a previous call to this routine that may be reused.
-*/
-static char *local_getline(char *zLine, FILE *in){
- int nLine = zLine==0 ? 0 : 100;
- int n = 0;
-
- while( 1 ){
- if( n+100>nLine ){
- nLine = nLine*2 + 100;
- zLine = realloc(zLine, nLine);
- if( zLine==0 ) return 0;
- }
- if( fgets(&zLine[n], nLine - n, in)==0 ){
- if( n==0 ){
- free(zLine);
- return 0;
- }
- zLine[n] = 0;
- break;
- }
- while( zLine[n] ) n++;
- if( n>0 && zLine[n-1]=='\n' ){
- n--;
- if( n>0 && zLine[n-1]=='\r' ) n--;
- zLine[n] = 0;
- break;
- }
- }
-#if defined(_WIN32) || defined(WIN32)
- /* For interactive input on Windows systems, translate the
- ** multi-byte characterset characters into UTF-8. */
- if( stdin_is_interactive && in==stdin ){
- char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
- if( zTrans ){
- int nTrans = strlen30(zTrans)+1;
- if( nTrans>nLine ){
- zLine = realloc(zLine, nTrans);
- if( zLine==0 ){
- sqlite3_free(zTrans);
- return 0;
- }
- }
- memcpy(zLine, zTrans, nTrans);
- sqlite3_free(zTrans);
- }
- }
-#endif /* defined(_WIN32) || defined(WIN32) */
- return zLine;
-}
-
-/*
-** Retrieve a single line of input text.
-**
-** If in==0 then read from standard input and prompt before each line.
-** If isContinuation is true, then a continuation prompt is appropriate.
-** If isContinuation is zero, then the main prompt should be used.
-**
-** If zPrior is not NULL then it is a buffer from a prior call to this
-** routine that can be reused.
-**
-** The result is stored in space obtained from malloc() and must either
-** be freed by the caller or else passed back into this routine via the
-** zPrior argument for reuse.
-*/
-static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
- char *zPrompt;
- char *zResult;
- if( in!=0 ){
- zResult = local_getline(zPrior, in);
- }else{
- zPrompt = isContinuation ? continuePrompt : mainPrompt;
-#if SHELL_USE_LOCAL_GETLINE
- printf("%s", zPrompt);
- fflush(stdout);
- zResult = local_getline(zPrior, stdin);
-#else
- free(zPrior);
- zResult = shell_readline(zPrompt);
- if( zResult && *zResult ) shell_add_history(zResult);
-#endif
- }
- return zResult;
-}
-/*
-** A variable length string to which one can append text.
-*/
-typedef struct ShellText ShellText;
-struct ShellText {
- char *z;
- int n;
- int nAlloc;
-};
-
-/*
-** Initialize and destroy a ShellText object
-*/
-static void initText(ShellText *p){
- memset(p, 0, sizeof(*p));
-}
-static void freeText(ShellText *p){
- free(p->z);
- initText(p);
-}
-
-/* zIn is either a pointer to a NULL-terminated string in memory obtained
-** from malloc(), or a NULL pointer. The string pointed to by zAppend is
-** added to zIn, and the result returned in memory obtained from malloc().
-** zIn, if it was not NULL, is freed.
-**
-** If the third argument, quote, is not '\0', then it is used as a
-** quote character for zAppend.
-*/
-static void appendText(ShellText *p, char const *zAppend, char quote){
- int len;
- int i;
- int nAppend = strlen30(zAppend);
-
- len = nAppend+p->n+1;
- if( quote ){
- len += 2;
- for(i=0; i<nAppend; i++){
- if( zAppend[i]==quote ) len++;
- }
- }
-
- if( p->n+len>=p->nAlloc ){
- p->nAlloc = p->nAlloc*2 + len + 20;
- p->z = realloc(p->z, p->nAlloc);
- if( p->z==0 ){
- memset(p, 0, sizeof(*p));
- return;
- }
- }
-
- if( quote ){
- char *zCsr = p->z+p->n;
- *zCsr++ = quote;
- for(i=0; i<nAppend; i++){
- *zCsr++ = zAppend[i];
- if( zAppend[i]==quote ) *zCsr++ = quote;
- }
- *zCsr++ = quote;
- p->n = (int)(zCsr - p->z);
- *zCsr = '\0';
- }else{
- memcpy(p->z+p->n, zAppend, nAppend);
- p->n += nAppend;
- p->z[p->n] = '\0';
- }
-}
-
-/*
-** Attempt to determine if identifier zName needs to be quoted, either
-** because it contains non-alphanumeric characters, or because it is an
-** SQLite keyword. Be conservative in this estimate: When in doubt assume
-** that quoting is required.
-**
-** Return '"' if quoting is required. Return 0 if no quoting is required.
-*/
-static char quoteChar(const char *zName){
- /* All SQLite keywords, in alphabetical order */
- static const char *azKeywords[] = {
- "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS",
- "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY",
- "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT",
- "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE",
- "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
- "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH",
- "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN",
- "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF",
- "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER",
- "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY",
- "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL",
- "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA",
- "PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP",
- "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT",
- "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP",
- "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE",
- "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE",
- "WITH", "WITHOUT",
- };
- int i, lwr, upr, mid, c;
- if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
- for(i=0; zName[i]; i++){
- if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
- }
- lwr = 0;
- upr = sizeof(azKeywords)/sizeof(azKeywords[0]) - 1;
- while( lwr<=upr ){
- mid = (lwr+upr)/2;
- c = sqlite3_stricmp(azKeywords[mid], zName);
- if( c==0 ) return '"';
- if( c<0 ){
- lwr = mid+1;
- }else{
- upr = mid-1;
- }
- }
- return 0;
-}
-
-/*
-** SQL function: shell_add_schema(S,X)
-**
-** Add the schema name X to the CREATE statement in S and return the result.
-** Examples:
-**
-** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x);
-**
-** Also works on
-**
-** CREATE INDEX
-** CREATE UNIQUE INDEX
-** CREATE VIEW
-** CREATE TRIGGER
-** CREATE VIRTUAL TABLE
-**
-** This UDF is used by the .schema command to insert the schema name of
-** attached databases into the middle of the sqlite_master.sql field.
-*/
-static void shellAddSchemaName(
- sqlite3_context *pCtx,
- int nVal,
- sqlite3_value **apVal
-){
- static const char *aPrefix[] = {
- "TABLE",
- "INDEX",
- "UNIQUE INDEX",
- "VIEW",
- "TRIGGER",
- "VIRTUAL TABLE"
- };
- int i = 0;
- const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
- const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
- assert( nVal==2 );
- if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
- for(i=0; i<(int)(sizeof(aPrefix)/sizeof(aPrefix[0])); i++){
- int n = strlen30(aPrefix[i]);
- if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
- char cQuote = quoteChar(zSchema);
- char *z;
- if( cQuote ){
- z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
- }else{
- z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
- }
- sqlite3_result_text(pCtx, z, -1, sqlite3_free);
- return;
- }
- }
- }
- sqlite3_result_value(pCtx, apVal[0]);
-}
-
-/*
-** The source code for several run-time loadable extensions is inserted
-** below by the ../tool/mkshellc.tcl script. Before processing that included
-** code, we need to override some macros to make the included program code
-** work here in the middle of this regular program.
-*/
-#define SQLITE_EXTENSION_INIT1
-#define SQLITE_EXTENSION_INIT2(X) (void)(X)
-
-/************************* Begin ../ext/misc/shathree.c ******************/
-/*
-** 2017-03-08
-**
-** 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 SQLite extension implements a functions that compute SHA1 hashes.
-** Two SQL functions are implemented:
-**
-** sha3(X,SIZE)
-** sha3_query(Y,SIZE)
-**
-** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
-** X is NULL.
-**
-** The sha3_query(Y) function evalutes all queries in the SQL statements of Y
-** and returns a hash of their results.
-**
-** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm
-** is used. If SIZE is included it must be one of the integers 224, 256,
-** 384, or 512, to determine SHA3 hash variant that is computed.
-*/
-SQLITE_EXTENSION_INIT1
-#include <assert.h>
-#include <string.h>
-#include <stdarg.h>
-typedef sqlite3_uint64 u64;
-
-/******************************************************************************
-** The Hash Engine
-*/
-/*
-** Macros to determine whether the machine is big or little endian,
-** and whether or not that determination is run-time or compile-time.
-**
-** For best performance, an attempt is made to guess at the byte-order
-** using C-preprocessor macros. If that is unsuccessful, or if
-** -DSHA3_BYTEORDER=0 is set, then byte-order is determined
-** at run-time.
-*/
-#ifndef SHA3_BYTEORDER
-# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
- defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
- defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
- defined(__arm__)
-# define SHA3_BYTEORDER 1234
-# elif defined(sparc) || defined(__ppc__)
-# define SHA3_BYTEORDER 4321
-# else
-# define SHA3_BYTEORDER 0
-# endif
-#endif
-
-
-/*
-** State structure for a SHA3 hash in progress
-*/
-typedef struct SHA3Context SHA3Context;
-struct SHA3Context {
- union {
- u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */
- unsigned char x[1600]; /* ... or 1600 bytes */
- } u;
- unsigned nRate; /* Bytes of input accepted per Keccak iteration */
- unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */
- unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
-};
-
-/*
-** A single step of the Keccak mixing function for a 1600-bit state
-*/
-static void KeccakF1600Step(SHA3Context *p){
- int i;
- u64 B0, B1, B2, B3, B4;
- u64 C0, C1, C2, C3, C4;
- u64 D0, D1, D2, D3, D4;
- static const u64 RC[] = {
- 0x0000000000000001ULL, 0x0000000000008082ULL,
- 0x800000000000808aULL, 0x8000000080008000ULL,
- 0x000000000000808bULL, 0x0000000080000001ULL,
- 0x8000000080008081ULL, 0x8000000000008009ULL,
- 0x000000000000008aULL, 0x0000000000000088ULL,
- 0x0000000080008009ULL, 0x000000008000000aULL,
- 0x000000008000808bULL, 0x800000000000008bULL,
- 0x8000000000008089ULL, 0x8000000000008003ULL,
- 0x8000000000008002ULL, 0x8000000000000080ULL,
- 0x000000000000800aULL, 0x800000008000000aULL,
- 0x8000000080008081ULL, 0x8000000000008080ULL,
- 0x0000000080000001ULL, 0x8000000080008008ULL
- };
-# define A00 (p->u.s[0])
-# define A01 (p->u.s[1])
-# define A02 (p->u.s[2])
-# define A03 (p->u.s[3])
-# define A04 (p->u.s[4])
-# define A10 (p->u.s[5])
-# define A11 (p->u.s[6])
-# define A12 (p->u.s[7])
-# define A13 (p->u.s[8])
-# define A14 (p->u.s[9])
-# define A20 (p->u.s[10])
-# define A21 (p->u.s[11])
-# define A22 (p->u.s[12])
-# define A23 (p->u.s[13])
-# define A24 (p->u.s[14])
-# define A30 (p->u.s[15])
-# define A31 (p->u.s[16])
-# define A32 (p->u.s[17])
-# define A33 (p->u.s[18])
-# define A34 (p->u.s[19])
-# define A40 (p->u.s[20])
-# define A41 (p->u.s[21])
-# define A42 (p->u.s[22])
-# define A43 (p->u.s[23])
-# define A44 (p->u.s[24])
-# define ROL64(a,x) ((a<<x)|(a>>(64-x)))
-
- for(i=0; i<24; i+=4){
- C0 = A00^A10^A20^A30^A40;
- C1 = A01^A11^A21^A31^A41;
- C2 = A02^A12^A22^A32^A42;
- C3 = A03^A13^A23^A33^A43;
- C4 = A04^A14^A24^A34^A44;
- D0 = C4^ROL64(C1, 1);
- D1 = C0^ROL64(C2, 1);
- D2 = C1^ROL64(C3, 1);
- D3 = C2^ROL64(C4, 1);
- D4 = C3^ROL64(C0, 1);
-
- B0 = (A00^D0);
- B1 = ROL64((A11^D1), 44);
- B2 = ROL64((A22^D2), 43);
- B3 = ROL64((A33^D3), 21);
- B4 = ROL64((A44^D4), 14);
- A00 = B0 ^((~B1)& B2 );
- A00 ^= RC[i];
- A11 = B1 ^((~B2)& B3 );
- A22 = B2 ^((~B3)& B4 );
- A33 = B3 ^((~B4)& B0 );
- A44 = B4 ^((~B0)& B1 );
-
- B2 = ROL64((A20^D0), 3);
- B3 = ROL64((A31^D1), 45);
- B4 = ROL64((A42^D2), 61);
- B0 = ROL64((A03^D3), 28);
- B1 = ROL64((A14^D4), 20);
- A20 = B0 ^((~B1)& B2 );
- A31 = B1 ^((~B2)& B3 );
- A42 = B2 ^((~B3)& B4 );
- A03 = B3 ^((~B4)& B0 );
- A14 = B4 ^((~B0)& B1 );
-
- B4 = ROL64((A40^D0), 18);
- B0 = ROL64((A01^D1), 1);
- B1 = ROL64((A12^D2), 6);
- B2 = ROL64((A23^D3), 25);
- B3 = ROL64((A34^D4), 8);
- A40 = B0 ^((~B1)& B2 );
- A01 = B1 ^((~B2)& B3 );
- A12 = B2 ^((~B3)& B4 );
- A23 = B3 ^((~B4)& B0 );
- A34 = B4 ^((~B0)& B1 );
-
- B1 = ROL64((A10^D0), 36);
- B2 = ROL64((A21^D1), 10);
- B3 = ROL64((A32^D2), 15);
- B4 = ROL64((A43^D3), 56);
- B0 = ROL64((A04^D4), 27);
- A10 = B0 ^((~B1)& B2 );
- A21 = B1 ^((~B2)& B3 );
- A32 = B2 ^((~B3)& B4 );
- A43 = B3 ^((~B4)& B0 );
- A04 = B4 ^((~B0)& B1 );
-
- B3 = ROL64((A30^D0), 41);
- B4 = ROL64((A41^D1), 2);
- B0 = ROL64((A02^D2), 62);
- B1 = ROL64((A13^D3), 55);
- B2 = ROL64((A24^D4), 39);
- A30 = B0 ^((~B1)& B2 );
- A41 = B1 ^((~B2)& B3 );
- A02 = B2 ^((~B3)& B4 );
- A13 = B3 ^((~B4)& B0 );
- A24 = B4 ^((~B0)& B1 );
-
- C0 = A00^A20^A40^A10^A30;
- C1 = A11^A31^A01^A21^A41;
- C2 = A22^A42^A12^A32^A02;
- C3 = A33^A03^A23^A43^A13;
- C4 = A44^A14^A34^A04^A24;
- D0 = C4^ROL64(C1, 1);
- D1 = C0^ROL64(C2, 1);
- D2 = C1^ROL64(C3, 1);
- D3 = C2^ROL64(C4, 1);
- D4 = C3^ROL64(C0, 1);
-
- B0 = (A00^D0);
- B1 = ROL64((A31^D1), 44);
- B2 = ROL64((A12^D2), 43);
- B3 = ROL64((A43^D3), 21);
- B4 = ROL64((A24^D4), 14);
- A00 = B0 ^((~B1)& B2 );
- A00 ^= RC[i+1];
- A31 = B1 ^((~B2)& B3 );
- A12 = B2 ^((~B3)& B4 );
- A43 = B3 ^((~B4)& B0 );
- A24 = B4 ^((~B0)& B1 );
-
- B2 = ROL64((A40^D0), 3);
- B3 = ROL64((A21^D1), 45);
- B4 = ROL64((A02^D2), 61);
- B0 = ROL64((A33^D3), 28);
- B1 = ROL64((A14^D4), 20);
- A40 = B0 ^((~B1)& B2 );
- A21 = B1 ^((~B2)& B3 );
- A02 = B2 ^((~B3)& B4 );
- A33 = B3 ^((~B4)& B0 );
- A14 = B4 ^((~B0)& B1 );
-
- B4 = ROL64((A30^D0), 18);
- B0 = ROL64((A11^D1), 1);
- B1 = ROL64((A42^D2), 6);
- B2 = ROL64((A23^D3), 25);
- B3 = ROL64((A04^D4), 8);
- A30 = B0 ^((~B1)& B2 );
- A11 = B1 ^((~B2)& B3 );
- A42 = B2 ^((~B3)& B4 );
- A23 = B3 ^((~B4)& B0 );
- A04 = B4 ^((~B0)& B1 );
-
- B1 = ROL64((A20^D0), 36);
- B2 = ROL64((A01^D1), 10);
- B3 = ROL64((A32^D2), 15);
- B4 = ROL64((A13^D3), 56);
- B0 = ROL64((A44^D4), 27);
- A20 = B0 ^((~B1)& B2 );
- A01 = B1 ^((~B2)& B3 );
- A32 = B2 ^((~B3)& B4 );
- A13 = B3 ^((~B4)& B0 );
- A44 = B4 ^((~B0)& B1 );
-
- B3 = ROL64((A10^D0), 41);
- B4 = ROL64((A41^D1), 2);
- B0 = ROL64((A22^D2), 62);
- B1 = ROL64((A03^D3), 55);
- B2 = ROL64((A34^D4), 39);
- A10 = B0 ^((~B1)& B2 );
- A41 = B1 ^((~B2)& B3 );
- A22 = B2 ^((~B3)& B4 );
- A03 = B3 ^((~B4)& B0 );
- A34 = B4 ^((~B0)& B1 );
-
- C0 = A00^A40^A30^A20^A10;
- C1 = A31^A21^A11^A01^A41;
- C2 = A12^A02^A42^A32^A22;
- C3 = A43^A33^A23^A13^A03;
- C4 = A24^A14^A04^A44^A34;
- D0 = C4^ROL64(C1, 1);
- D1 = C0^ROL64(C2, 1);
- D2 = C1^ROL64(C3, 1);
- D3 = C2^ROL64(C4, 1);
- D4 = C3^ROL64(C0, 1);
-
- B0 = (A00^D0);
- B1 = ROL64((A21^D1), 44);
- B2 = ROL64((A42^D2), 43);
- B3 = ROL64((A13^D3), 21);
- B4 = ROL64((A34^D4), 14);
- A00 = B0 ^((~B1)& B2 );
- A00 ^= RC[i+2];
- A21 = B1 ^((~B2)& B3 );
- A42 = B2 ^((~B3)& B4 );
- A13 = B3 ^((~B4)& B0 );
- A34 = B4 ^((~B0)& B1 );
-
- B2 = ROL64((A30^D0), 3);
- B3 = ROL64((A01^D1), 45);
- B4 = ROL64((A22^D2), 61);
- B0 = ROL64((A43^D3), 28);
- B1 = ROL64((A14^D4), 20);
- A30 = B0 ^((~B1)& B2 );
- A01 = B1 ^((~B2)& B3 );
- A22 = B2 ^((~B3)& B4 );
- A43 = B3 ^((~B4)& B0 );
- A14 = B4 ^((~B0)& B1 );
-
- B4 = ROL64((A10^D0), 18);
- B0 = ROL64((A31^D1), 1);
- B1 = ROL64((A02^D2), 6);
- B2 = ROL64((A23^D3), 25);
- B3 = ROL64((A44^D4), 8);
- A10 = B0 ^((~B1)& B2 );
- A31 = B1 ^((~B2)& B3 );
- A02 = B2 ^((~B3)& B4 );
- A23 = B3 ^((~B4)& B0 );
- A44 = B4 ^((~B0)& B1 );
-
- B1 = ROL64((A40^D0), 36);
- B2 = ROL64((A11^D1), 10);
- B3 = ROL64((A32^D2), 15);
- B4 = ROL64((A03^D3), 56);
- B0 = ROL64((A24^D4), 27);
- A40 = B0 ^((~B1)& B2 );
- A11 = B1 ^((~B2)& B3 );
- A32 = B2 ^((~B3)& B4 );
- A03 = B3 ^((~B4)& B0 );
- A24 = B4 ^((~B0)& B1 );
-
- B3 = ROL64((A20^D0), 41);
- B4 = ROL64((A41^D1), 2);
- B0 = ROL64((A12^D2), 62);
- B1 = ROL64((A33^D3), 55);
- B2 = ROL64((A04^D4), 39);
- A20 = B0 ^((~B1)& B2 );
- A41 = B1 ^((~B2)& B3 );
- A12 = B2 ^((~B3)& B4 );
- A33 = B3 ^((~B4)& B0 );
- A04 = B4 ^((~B0)& B1 );
-
- C0 = A00^A30^A10^A40^A20;
- C1 = A21^A01^A31^A11^A41;
- C2 = A42^A22^A02^A32^A12;
- C3 = A13^A43^A23^A03^A33;
- C4 = A34^A14^A44^A24^A04;
- D0 = C4^ROL64(C1, 1);
- D1 = C0^ROL64(C2, 1);
- D2 = C1^ROL64(C3, 1);
- D3 = C2^ROL64(C4, 1);
- D4 = C3^ROL64(C0, 1);
-
- B0 = (A00^D0);
- B1 = ROL64((A01^D1), 44);
- B2 = ROL64((A02^D2), 43);
- B3 = ROL64((A03^D3), 21);
- B4 = ROL64((A04^D4), 14);
- A00 = B0 ^((~B1)& B2 );
- A00 ^= RC[i+3];
- A01 = B1 ^((~B2)& B3 );
- A02 = B2 ^((~B3)& B4 );
- A03 = B3 ^((~B4)& B0 );
- A04 = B4 ^((~B0)& B1 );
-
- B2 = ROL64((A10^D0), 3);
- B3 = ROL64((A11^D1), 45);
- B4 = ROL64((A12^D2), 61);
- B0 = ROL64((A13^D3), 28);
- B1 = ROL64((A14^D4), 20);
- A10 = B0 ^((~B1)& B2 );
- A11 = B1 ^((~B2)& B3 );
- A12 = B2 ^((~B3)& B4 );
- A13 = B3 ^((~B4)& B0 );
- A14 = B4 ^((~B0)& B1 );
-
- B4 = ROL64((A20^D0), 18);
- B0 = ROL64((A21^D1), 1);
- B1 = ROL64((A22^D2), 6);
- B2 = ROL64((A23^D3), 25);
- B3 = ROL64((A24^D4), 8);
- A20 = B0 ^((~B1)& B2 );
- A21 = B1 ^((~B2)& B3 );
- A22 = B2 ^((~B3)& B4 );
- A23 = B3 ^((~B4)& B0 );
- A24 = B4 ^((~B0)& B1 );
-
- B1 = ROL64((A30^D0), 36);
- B2 = ROL64((A31^D1), 10);
- B3 = ROL64((A32^D2), 15);
- B4 = ROL64((A33^D3), 56);
- B0 = ROL64((A34^D4), 27);
- A30 = B0 ^((~B1)& B2 );
- A31 = B1 ^((~B2)& B3 );
- A32 = B2 ^((~B3)& B4 );
- A33 = B3 ^((~B4)& B0 );
- A34 = B4 ^((~B0)& B1 );
-
- B3 = ROL64((A40^D0), 41);
- B4 = ROL64((A41^D1), 2);
- B0 = ROL64((A42^D2), 62);
- B1 = ROL64((A43^D3), 55);
- B2 = ROL64((A44^D4), 39);
- A40 = B0 ^((~B1)& B2 );
- A41 = B1 ^((~B2)& B3 );
- A42 = B2 ^((~B3)& B4 );
- A43 = B3 ^((~B4)& B0 );
- A44 = B4 ^((~B0)& B1 );
- }
-}
-
-/*
-** Initialize a new hash. iSize determines the size of the hash
-** in bits and should be one of 224, 256, 384, or 512. Or iSize
-** can be zero to use the default hash size of 256 bits.
-*/
-static void SHA3Init(SHA3Context *p, int iSize){
- memset(p, 0, sizeof(*p));
- if( iSize>=128 && iSize<=512 ){
- p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
- }else{
- p->nRate = (1600 - 2*256)/8;
- }
-#if SHA3_BYTEORDER==1234
- /* Known to be little-endian at compile-time. No-op */
-#elif SHA3_BYTEORDER==4321
- p->ixMask = 7; /* Big-endian */
-#else
- {
- static unsigned int one = 1;
- if( 1==*(unsigned char*)&one ){
- /* Little endian. No byte swapping. */
- p->ixMask = 0;
- }else{
- /* Big endian. Byte swap. */
- p->ixMask = 7;
- }
- }
-#endif
-}
-
-/*
-** Make consecutive calls to the SHA3Update function to add new content
-** to the hash
-*/
-static void SHA3Update(
- SHA3Context *p,
- const unsigned char *aData,
- unsigned int nData
-){
- unsigned int i = 0;
-#if SHA3_BYTEORDER==1234
- if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
- for(; i+7<nData; i+=8){
- p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
- p->nLoaded += 8;
- if( p->nLoaded>=p->nRate ){
- KeccakF1600Step(p);
- p->nLoaded = 0;
- }
- }
- }
-#endif
- for(; i<nData; i++){
-#if SHA3_BYTEORDER==1234
- p->u.x[p->nLoaded] ^= aData[i];
-#elif SHA3_BYTEORDER==4321
- p->u.x[p->nLoaded^0x07] ^= aData[i];
-#else
- p->u.x[p->nLoaded^p->ixMask] ^= aData[i];
-#endif
- p->nLoaded++;
- if( p->nLoaded==p->nRate ){
- KeccakF1600Step(p);
- p->nLoaded = 0;
- }
- }
-}
-
-/*
-** After all content has been added, invoke SHA3Final() to compute
-** the final hash. The function returns a pointer to the binary
-** hash value.
-*/
-static unsigned char *SHA3Final(SHA3Context *p){
- unsigned int i;
- if( p->nLoaded==p->nRate-1 ){
- const unsigned char c1 = 0x86;
- SHA3Update(p, &c1, 1);
- }else{
- const unsigned char c2 = 0x06;
- const unsigned char c3 = 0x80;
- SHA3Update(p, &c2, 1);
- p->nLoaded = p->nRate - 1;
- SHA3Update(p, &c3, 1);
- }
- for(i=0; i<p->nRate; i++){
- p->u.x[i+p->nRate] = p->u.x[i^p->ixMask];
- }
- return &p->u.x[p->nRate];
-}
-/* End of the hashing logic
-*****************************************************************************/
-
-/*
-** Implementation of the sha3(X,SIZE) function.
-**
-** Return a BLOB which is the SIZE-bit SHA3 hash of X. The default
-** size is 256. If X is a BLOB, it is hashed as is.
-** For all other non-NULL types of input, X is converted into a UTF-8 string
-** and the string is hashed without the trailing 0x00 terminator. The hash
-** of a NULL value is NULL.
-*/
-static void sha3Func(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- SHA3Context cx;
- int eType = sqlite3_value_type(argv[0]);
- int nByte = sqlite3_value_bytes(argv[0]);
- int iSize;
- if( argc==1 ){
- iSize = 256;
- }else{
- iSize = sqlite3_value_int(argv[1]);
- if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
- sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
- "384 512", -1);
- return;
- }
- }
- if( eType==SQLITE_NULL ) return;
- SHA3Init(&cx, iSize);
- if( eType==SQLITE_BLOB ){
- SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte);
- }else{
- SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte);
- }
- sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
-}
-
-/* Compute a string using sqlite3_vsnprintf() with a maximum length
-** of 50 bytes and add it to the hash.
-*/
-static void hash_step_vformat(
- SHA3Context *p, /* Add content to this context */
- const char *zFormat,
- ...
-){
- va_list ap;
- int n;
- char zBuf[50];
- va_start(ap, zFormat);
- sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
- va_end(ap);
- n = (int)strlen(zBuf);
- SHA3Update(p, (unsigned char*)zBuf, n);
-}
-
-/*
-** Implementation of the sha3_query(SQL,SIZE) function.
-**
-** This function compiles and runs the SQL statement(s) given in the
-** argument. The results are hashed using a SIZE-bit SHA3. The default
-** size is 256.
-**
-** The format of the byte stream that is hashed is summarized as follows:
-**
-** S<n>:<sql>
-** R
-** N
-** I<int>
-** F<ieee-float>
-** B<size>:<bytes>
-** T<size>:<text>
-**
-** <sql> is the original SQL text for each statement run and <n> is
-** the size of that text. The SQL text is UTF-8. A single R character
-** occurs before the start of each row. N means a NULL value.
-** I mean an 8-byte little-endian integer <int>. F is a floating point
-** number with an 8-byte little-endian IEEE floating point value <ieee-float>.
-** B means blobs of <size> bytes. T means text rendered as <size>
-** bytes of UTF-8. The <n> and <size> values are expressed as an ASCII
-** text integers.
-**
-** For each SQL statement in the X input, there is one S segment. Each
-** S segment is followed by zero or more R segments, one for each row in the
-** result set. After each R, there are one or more N, I, F, B, or T segments,
-** one for each column in the result set. Segments are concatentated directly
-** with no delimiters of any kind.
-*/
-static void sha3QueryFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- sqlite3 *db = sqlite3_context_db_handle(context);
- const char *zSql = (const char*)sqlite3_value_text(argv[0]);
- sqlite3_stmt *pStmt = 0;
- int nCol; /* Number of columns in the result set */
- int i; /* Loop counter */
- int rc;
- int n;
- const char *z;
- SHA3Context cx;
- int iSize;
-
- if( argc==1 ){
- iSize = 256;
- }else{
- iSize = sqlite3_value_int(argv[1]);
- if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
- sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
- "384 512", -1);
- return;
- }
- }
- if( zSql==0 ) return;
- SHA3Init(&cx, iSize);
- while( zSql[0] ){
- rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
- if( rc ){
- char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
- zSql, sqlite3_errmsg(db));
- sqlite3_finalize(pStmt);
- sqlite3_result_error(context, zMsg, -1);
- sqlite3_free(zMsg);
- return;
- }
- if( !sqlite3_stmt_readonly(pStmt) ){
- char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
- sqlite3_finalize(pStmt);
- sqlite3_result_error(context, zMsg, -1);
- sqlite3_free(zMsg);
- return;
- }
- nCol = sqlite3_column_count(pStmt);
- z = sqlite3_sql(pStmt);
- n = (int)strlen(z);
- hash_step_vformat(&cx,"S%d:",n);
- SHA3Update(&cx,(unsigned char*)z,n);
-
- /* Compute a hash over the result of the query */
- while( SQLITE_ROW==sqlite3_step(pStmt) ){
- SHA3Update(&cx,(const unsigned char*)"R",1);
- for(i=0; i<nCol; i++){
- switch( sqlite3_column_type(pStmt,i) ){
- case SQLITE_NULL: {
- SHA3Update(&cx, (const unsigned char*)"N",1);
- break;
- }
- case SQLITE_INTEGER: {
- sqlite3_uint64 u;
- int j;
- unsigned char x[9];
- sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
- memcpy(&u, &v, 8);
- for(j=8; j>=1; j--){
- x[j] = u & 0xff;
- u >>= 8;
- }
- x[0] = 'I';
- SHA3Update(&cx, x, 9);
- break;
- }
- case SQLITE_FLOAT: {
- sqlite3_uint64 u;
- int j;
- unsigned char x[9];
- double r = sqlite3_column_double(pStmt,i);
- memcpy(&u, &r, 8);
- for(j=8; j>=1; j--){
- x[j] = u & 0xff;
- u >>= 8;
- }
- x[0] = 'F';
- SHA3Update(&cx,x,9);
- break;
- }
- case SQLITE_TEXT: {
- int n2 = sqlite3_column_bytes(pStmt, i);
- const unsigned char *z2 = sqlite3_column_text(pStmt, i);
- hash_step_vformat(&cx,"T%d:",n2);
- SHA3Update(&cx, z2, n2);
- break;
- }
- case SQLITE_BLOB: {
- int n2 = sqlite3_column_bytes(pStmt, i);
- const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
- hash_step_vformat(&cx,"B%d:",n2);
- SHA3Update(&cx, z2, n2);
- break;
- }
- }
- }
- }
- sqlite3_finalize(pStmt);
- }
- sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
-}
-
-
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-int sqlite3_shathree_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
-){
- int rc = SQLITE_OK;
- SQLITE_EXTENSION_INIT2(pApi);
- (void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "sha3", 1, SQLITE_UTF8, 0,
- sha3Func, 0, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8, 0,
- sha3Func, 0, 0);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8, 0,
- sha3QueryFunc, 0, 0);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8, 0,
- sha3QueryFunc, 0, 0);
- }
- return rc;
-}
-
-/************************* End ../ext/misc/shathree.c ********************/
-/************************* Begin ../ext/misc/fileio.c ******************/
-/*
-** 2014-06-13
-**
-** 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 SQLite extension implements SQL functions readfile() and
-** writefile().
-*/
-SQLITE_EXTENSION_INIT1
-#include <stdio.h>
-
-/*
-** Implementation of the "readfile(X)" SQL function. The entire content
-** of the file named X is read and returned as a BLOB. NULL is returned
-** if the file does not exist or is unreadable.
-*/
-static void readfileFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- const char *zName;
- FILE *in;
- long nIn;
- void *pBuf;
-
- (void)(argc); /* Unused parameter */
- zName = (const char*)sqlite3_value_text(argv[0]);
- if( zName==0 ) return;
- in = fopen(zName, "rb");
- if( in==0 ) return;
- fseek(in, 0, SEEK_END);
- nIn = ftell(in);
- rewind(in);
- pBuf = sqlite3_malloc( nIn );
- if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
- sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
- }else{
- sqlite3_free(pBuf);
- }
- fclose(in);
-}
-
-/*
-** Implementation of the "writefile(X,Y)" SQL function. The argument Y
-** is written into file X. The number of bytes written is returned. Or
-** NULL is returned if something goes wrong, such as being unable to open
-** file X for writing.
-*/
-static void writefileFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- FILE *out;
- const char *z;
- sqlite3_int64 rc;
- const char *zFile;
-
- (void)(argc); /* Unused parameter */
- zFile = (const char*)sqlite3_value_text(argv[0]);
- if( zFile==0 ) return;
- out = fopen(zFile, "wb");
- if( out==0 ) return;
- z = (const char*)sqlite3_value_blob(argv[1]);
- if( z==0 ){
- rc = 0;
- }else{
- rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
- }
- fclose(out);
- sqlite3_result_int64(context, rc);
-}
-
-
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-int sqlite3_fileio_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
-){
- int rc = SQLITE_OK;
- SQLITE_EXTENSION_INIT2(pApi);
- (void)pzErrMsg; /* Unused parameter */
- rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
- readfileFunc, 0, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "writefile", 2, SQLITE_UTF8, 0,
- writefileFunc, 0, 0);
- }
- return rc;
-}
-
-/************************* End ../ext/misc/fileio.c ********************/
-/************************* Begin ../ext/misc/completion.c ******************/
-/*
-** 2017-07-10
-**
-** 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 an eponymous virtual table that returns suggested
-** completions for a partial SQL input.
-**
-** Suggested usage:
-**
-** SELECT DISTINCT candidate COLLATE nocase
-** FROM completion($prefix,$wholeline)
-** ORDER BY 1;
-**
-** The two query parameters are optional. $prefix is the text of the
-** current word being typed and that is to be completed. $wholeline is
-** the complete input line, used for context.
-**
-** The raw completion() table might return the same candidate multiple
-** times, for example if the same column name is used to two or more
-** tables. And the candidates are returned in an arbitrary order. Hence,
-** the DISTINCT and ORDER BY are recommended.
-**
-** This virtual table operates at the speed of human typing, and so there
-** is no attempt to make it fast. Even a slow implementation will be much
-** faster than any human can type.
-**
-*/
-SQLITE_EXTENSION_INIT1
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-
-#ifndef SQLITE_OMIT_VIRTUALTABLE
-
-/* completion_vtab is a subclass of sqlite3_vtab which will
-** serve as the underlying representation of a completion virtual table
-*/
-typedef struct completion_vtab completion_vtab;
-struct completion_vtab {
- sqlite3_vtab base; /* Base class - must be first */
- sqlite3 *db; /* Database connection for this completion vtab */
-};
-
-/* completion_cursor is a subclass of sqlite3_vtab_cursor which will
-** serve as the underlying representation of a cursor that scans
-** over rows of the result
-*/
-typedef struct completion_cursor completion_cursor;
-struct completion_cursor {
- sqlite3_vtab_cursor base; /* Base class - must be first */
- sqlite3 *db; /* Database connection for this cursor */
- int nPrefix, nLine; /* Number of bytes in zPrefix and zLine */
- char *zPrefix; /* The prefix for the word we want to complete */
- char *zLine; /* The whole that we want to complete */
- const char *zCurrentRow; /* Current output row */
- sqlite3_stmt *pStmt; /* Current statement */
- sqlite3_int64 iRowid; /* The rowid */
- int ePhase; /* Current phase */
- int j; /* inter-phase counter */
-};
-
-/* Values for ePhase:
-*/
-#define COMPLETION_FIRST_PHASE 1
-#define COMPLETION_KEYWORDS 1
-#define COMPLETION_PRAGMAS 2
-#define COMPLETION_FUNCTIONS 3
-#define COMPLETION_COLLATIONS 4
-#define COMPLETION_INDEXES 5
-#define COMPLETION_TRIGGERS 6
-#define COMPLETION_DATABASES 7
-#define COMPLETION_TABLES 8
-#define COMPLETION_COLUMNS 9
-#define COMPLETION_MODULES 10
-#define COMPLETION_EOF 11
-
-/*
-** The completionConnect() method is invoked to create a new
-** completion_vtab that describes the completion virtual table.
-**
-** Think of this routine as the constructor for completion_vtab objects.
-**
-** All this routine needs to do is:
-**
-** (1) Allocate the completion_vtab object and initialize all fields.
-**
-** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
-** result set of queries against completion will look like.
-*/
-static int completionConnect(
- sqlite3 *db,
- void *pAux,
- int argc, const char *const*argv,
- sqlite3_vtab **ppVtab,
- char **pzErr
-){
- completion_vtab *pNew;
- int rc;
-
- (void)(pAux); /* Unused parameter */
- (void)(argc); /* Unused parameter */
- (void)(argv); /* Unused parameter */
- (void)(pzErr); /* Unused parameter */
-
-/* Column numbers */
-#define COMPLETION_COLUMN_CANDIDATE 0 /* Suggested completion of the input */
-#define COMPLETION_COLUMN_PREFIX 1 /* Prefix of the word to be completed */
-#define COMPLETION_COLUMN_WHOLELINE 2 /* Entire line seen so far */
-#define COMPLETION_COLUMN_PHASE 3 /* ePhase - used for debugging only */
-
- rc = sqlite3_declare_vtab(db,
- "CREATE TABLE x("
- " candidate TEXT,"
- " prefix TEXT HIDDEN,"
- " wholeline TEXT HIDDEN,"
- " phase INT HIDDEN" /* Used for debugging only */
- ")");
- 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;
- }
- return rc;
-}
-
-/*
-** This method is the destructor for completion_cursor objects.
-*/
-static int completionDisconnect(sqlite3_vtab *pVtab){
- sqlite3_free(pVtab);
- return SQLITE_OK;
-}
-
-/*
-** Constructor for a new completion_cursor object.
-*/
-static int completionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
- completion_cursor *pCur;
- pCur = sqlite3_malloc( sizeof(*pCur) );
- if( pCur==0 ) return SQLITE_NOMEM;
- memset(pCur, 0, sizeof(*pCur));
- pCur->db = ((completion_vtab*)p)->db;
- *ppCursor = &pCur->base;
- return SQLITE_OK;
-}
-
-/*
-** Reset the completion_cursor.
-*/
-static void completionCursorReset(completion_cursor *pCur){
- sqlite3_free(pCur->zPrefix); pCur->zPrefix = 0; pCur->nPrefix = 0;
- sqlite3_free(pCur->zLine); pCur->zLine = 0; pCur->nLine = 0;
- sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0;
- pCur->j = 0;
-}
-
-/*
-** Destructor for a completion_cursor.
-*/
-static int completionClose(sqlite3_vtab_cursor *cur){
- completionCursorReset((completion_cursor*)cur);
- sqlite3_free(cur);
- return SQLITE_OK;
-}
-
-/*
-** All SQL keywords understood by SQLite
-*/
-static const char *completionKwrds[] = {
- "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS",
- "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY",
- "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT",
- "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE",
- "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
- "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH",
- "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN",
- "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", "GROUP", "HAVING", "IF",
- "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER",
- "INSERT", "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY",
- "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", "NOTNULL",
- "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA",
- "PRIMARY", "QUERY", "RAISE", "RECURSIVE", "REFERENCES", "REGEXP",
- "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT",
- "ROLLBACK", "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP",
- "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", "UNIQUE",
- "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE",
- "WITH", "WITHOUT",
-};
-#define completionKwCount \
- (int)(sizeof(completionKwrds)/sizeof(completionKwrds[0]))
-
-/*
-** Advance a completion_cursor to its next row of output.
-**
-** The ->ePhase, ->j, and ->pStmt fields of the completion_cursor object
-** record the current state of the scan. This routine sets ->zCurrentRow
-** to the current row of output and then returns. If no more rows remain,
-** then ->ePhase is set to COMPLETION_EOF which will signal the virtual
-** table that has reached the end of its scan.
-**
-** The current implementation just lists potential identifiers and
-** keywords and filters them by zPrefix. Future enhancements should
-** take zLine into account to try to restrict the set of identifiers and
-** keywords based on what would be legal at the current point of input.
-*/
-static int completionNext(sqlite3_vtab_cursor *cur){
- completion_cursor *pCur = (completion_cursor*)cur;
- int eNextPhase = 0; /* Next phase to try if current phase reaches end */
- int iCol = -1; /* If >=0, step pCur->pStmt and use the i-th column */
- pCur->iRowid++;
- while( pCur->ePhase!=COMPLETION_EOF ){
- switch( pCur->ePhase ){
- case COMPLETION_KEYWORDS: {
- if( pCur->j >= completionKwCount ){
- pCur->zCurrentRow = 0;
- pCur->ePhase = COMPLETION_DATABASES;
- }else{
- pCur->zCurrentRow = completionKwrds[pCur->j++];
- }
- iCol = -1;
- break;
- }
- case COMPLETION_DATABASES: {
- if( pCur->pStmt==0 ){
- sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1,
- &pCur->pStmt, 0);
- }
- iCol = 1;
- eNextPhase = COMPLETION_TABLES;
- break;
- }
- case COMPLETION_TABLES: {
- if( pCur->pStmt==0 ){
- sqlite3_stmt *pS2;
- char *zSql = 0;
- const char *zSep = "";
- sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
- while( sqlite3_step(pS2)==SQLITE_ROW ){
- const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
- zSql = sqlite3_mprintf(
- "%z%s"
- "SELECT name FROM \"%w\".sqlite_master"
- " WHERE type='table'",
- zSql, zSep, zDb
- );
- if( zSql==0 ) return SQLITE_NOMEM;
- zSep = " UNION ";
- }
- sqlite3_finalize(pS2);
- sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
- sqlite3_free(zSql);
- }
- iCol = 0;
- eNextPhase = COMPLETION_COLUMNS;
- break;
- }
- case COMPLETION_COLUMNS: {
- if( pCur->pStmt==0 ){
- sqlite3_stmt *pS2;
- char *zSql = 0;
- const char *zSep = "";
- sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
- while( sqlite3_step(pS2)==SQLITE_ROW ){
- const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
- zSql = sqlite3_mprintf(
- "%z%s"
- "SELECT pti.name FROM \"%w\".sqlite_master AS sm"
- " JOIN pragma_table_info(sm.name,%Q) AS pti"
- " WHERE sm.type='table'",
- zSql, zSep, zDb, zDb
- );
- if( zSql==0 ) return SQLITE_NOMEM;
- zSep = " UNION ";
- }
- sqlite3_finalize(pS2);
- sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
- sqlite3_free(zSql);
- }
- iCol = 0;
- eNextPhase = COMPLETION_EOF;
- break;
- }
- }
- if( iCol<0 ){
- /* This case is when the phase presets zCurrentRow */
- if( pCur->zCurrentRow==0 ) continue;
- }else{
- if( sqlite3_step(pCur->pStmt)==SQLITE_ROW ){
- /* Extract the next row of content */
- pCur->zCurrentRow = (const char*)sqlite3_column_text(pCur->pStmt, iCol);
- }else{
- /* When all rows are finished, advance to the next phase */
- sqlite3_finalize(pCur->pStmt);
- pCur->pStmt = 0;
- pCur->ePhase = eNextPhase;
- continue;
- }
- }
- if( pCur->nPrefix==0 ) break;
- if( sqlite3_strnicmp(pCur->zPrefix, pCur->zCurrentRow, pCur->nPrefix)==0 ){
- break;
- }
- }
-
- return SQLITE_OK;
-}
-
-/*
-** Return values of columns for the row at which the completion_cursor
-** is currently pointing.
-*/
-static int completionColumn(
- sqlite3_vtab_cursor *cur, /* The cursor */
- sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
- int i /* Which column to return */
-){
- completion_cursor *pCur = (completion_cursor*)cur;
- switch( i ){
- case COMPLETION_COLUMN_CANDIDATE: {
- sqlite3_result_text(ctx, pCur->zCurrentRow, -1, SQLITE_TRANSIENT);
- break;
- }
- case COMPLETION_COLUMN_PREFIX: {
- sqlite3_result_text(ctx, pCur->zPrefix, -1, SQLITE_TRANSIENT);
- break;
- }
- case COMPLETION_COLUMN_WHOLELINE: {
- sqlite3_result_text(ctx, pCur->zLine, -1, SQLITE_TRANSIENT);
- break;
- }
- case COMPLETION_COLUMN_PHASE: {
- sqlite3_result_int(ctx, pCur->ePhase);
- 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 completionRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
- completion_cursor *pCur = (completion_cursor*)cur;
- *pRowid = pCur->iRowid;
- return SQLITE_OK;
-}
-
-/*
-** Return TRUE if the cursor has been moved off of the last
-** row of output.
-*/
-static int completionEof(sqlite3_vtab_cursor *cur){
- completion_cursor *pCur = (completion_cursor*)cur;
- return pCur->ePhase >= COMPLETION_EOF;
-}
-
-/*
-** This method is called to "rewind" the completion_cursor object back
-** to the first row of output. This method is always called at least
-** once prior to any call to completionColumn() or completionRowid() or
-** completionEof().
-*/
-static int completionFilter(
- sqlite3_vtab_cursor *pVtabCursor,
- int idxNum, const char *idxStr,
- int argc, sqlite3_value **argv
-){
- completion_cursor *pCur = (completion_cursor *)pVtabCursor;
- int iArg = 0;
- (void)(idxStr); /* Unused parameter */
- (void)(argc); /* Unused parameter */
- completionCursorReset(pCur);
- if( idxNum & 1 ){
- pCur->nPrefix = sqlite3_value_bytes(argv[iArg]);
- if( pCur->nPrefix>0 ){
- pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
- if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
- }
- iArg++;
- }
- if( idxNum & 2 ){
- pCur->nLine = sqlite3_value_bytes(argv[iArg]);
- if( pCur->nLine>0 ){
- pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
- if( pCur->zLine==0 ) return SQLITE_NOMEM;
- }
- iArg++;
- }
- if( pCur->zLine!=0 && pCur->zPrefix==0 ){
- int i = pCur->nLine;
- while( i>0 && (isalnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){
- i--;
- }
- pCur->nPrefix = pCur->nLine - i;
- if( pCur->nPrefix>0 ){
- pCur->zPrefix = sqlite3_mprintf("%.*s", pCur->nPrefix, pCur->zLine + i);
- if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
- }
- }
- pCur->iRowid = 0;
- pCur->ePhase = COMPLETION_FIRST_PHASE;
- return completionNext(pVtabCursor);
-}
-
-/*
-** SQLite will invoke this method one or more times while planning a query
-** that uses the completion virtual table. This routine needs to create
-** a query plan for each invocation and compute an estimated cost for that
-** plan.
-**
-** There are two hidden parameters that act as arguments to the table-valued
-** function: "prefix" and "wholeline". Bit 0 of idxNum is set if "prefix"
-** is available and bit 1 is set if "wholeline" is available.
-*/
-static int completionBestIndex(
- sqlite3_vtab *tab,
- sqlite3_index_info *pIdxInfo
-){
- int i; /* Loop over constraints */
- int idxNum = 0; /* The query plan bitmask */
- int prefixIdx = -1; /* Index of the start= constraint, or -1 if none */
- int wholelineIdx = -1; /* Index of the stop= constraint, or -1 if none */
- int nArg = 0; /* Number of arguments that completeFilter() expects */
- const struct sqlite3_index_constraint *pConstraint;
-
- (void)(tab); /* Unused parameter */
- pConstraint = pIdxInfo->aConstraint;
- for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
- if( pConstraint->usable==0 ) continue;
- if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
- switch( pConstraint->iColumn ){
- case COMPLETION_COLUMN_PREFIX:
- prefixIdx = i;
- idxNum |= 1;
- break;
- case COMPLETION_COLUMN_WHOLELINE:
- wholelineIdx = i;
- idxNum |= 2;
- break;
- }
- }
- if( prefixIdx>=0 ){
- pIdxInfo->aConstraintUsage[prefixIdx].argvIndex = ++nArg;
- pIdxInfo->aConstraintUsage[prefixIdx].omit = 1;
- }
- if( wholelineIdx>=0 ){
- pIdxInfo->aConstraintUsage[wholelineIdx].argvIndex = ++nArg;
- pIdxInfo->aConstraintUsage[wholelineIdx].omit = 1;
- }
- pIdxInfo->idxNum = idxNum;
- pIdxInfo->estimatedCost = (double)5000 - 1000*nArg;
- pIdxInfo->estimatedRows = 500 - 100*nArg;
- return SQLITE_OK;
-}
-
-/*
-** This following structure defines all the methods for the
-** completion virtual table.
-*/
-static sqlite3_module completionModule = {
- 0, /* iVersion */
- 0, /* xCreate */
- completionConnect, /* xConnect */
- completionBestIndex, /* xBestIndex */
- completionDisconnect, /* xDisconnect */
- 0, /* xDestroy */
- completionOpen, /* xOpen - open a cursor */
- completionClose, /* xClose - close a cursor */
- completionFilter, /* xFilter - configure scan constraints */
- completionNext, /* xNext - advance a cursor */
- completionEof, /* xEof - check for end of scan */
- completionColumn, /* xColumn - read data */
- completionRowid, /* xRowid - read data */
- 0, /* xUpdate */
- 0, /* xBegin */
- 0, /* xSync */
- 0, /* xCommit */
- 0, /* xRollback */
- 0, /* xFindMethod */
- 0, /* xRename */
- 0, /* xSavepoint */
- 0, /* xRelease */
- 0 /* xRollbackTo */
-};
-
-#endif /* SQLITE_OMIT_VIRTUALTABLE */
-
-int sqlite3CompletionVtabInit(sqlite3 *db){
- int rc = SQLITE_OK;
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- rc = sqlite3_create_module(db, "completion", &completionModule, 0);
-#endif
- return rc;
-}
-
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-int sqlite3_completion_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
-){
- int rc = SQLITE_OK;
- SQLITE_EXTENSION_INIT2(pApi);
- (void)(pzErrMsg); /* Unused parameter */
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- rc = sqlite3CompletionVtabInit(db);
-#endif
- return rc;
-}
-
-/************************* End ../ext/misc/completion.c ********************/
-
-#if defined(SQLITE_ENABLE_SESSION)
-/*
-** State information for a single open session
-*/
-typedef struct OpenSession OpenSession;
-struct OpenSession {
- char *zName; /* Symbolic name for this session */
- int nFilter; /* Number of xFilter rejection GLOB patterns */
- char **azFilter; /* Array of xFilter rejection GLOB patterns */
- sqlite3_session *p; /* The open session */
-};
-#endif
-
-/*
-** Shell output mode information from before ".explain on",
-** saved so that it can be restored by ".explain off"
-*/
-typedef struct SavedModeInfo SavedModeInfo;
-struct SavedModeInfo {
- int valid; /* Is there legit data in here? */
- int mode; /* Mode prior to ".explain on" */
- int showHeader; /* The ".header" setting prior to ".explain on" */
- int colWidth[100]; /* Column widths prior to ".explain on" */
-};
-
-/*
-** State information about the database connection is contained in an
-** instance of the following structure.
-*/
-typedef struct ShellState ShellState;
-struct ShellState {
- sqlite3 *db; /* The database */
- int autoExplain; /* Automatically turn on .explain mode */
- int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
- int statsOn; /* True to display memory stats before each finalize */
- int scanstatsOn; /* True to display scan stats before each finalize */
- int outCount; /* Revert to stdout when reaching zero */
- int cnt; /* Number of records displayed so far */
- FILE *out; /* Write results here */
- FILE *traceOut; /* Output for sqlite3_trace() */
- int nErr; /* Number of errors seen */
- int mode; /* An output mode setting */
- int cMode; /* temporary output mode for the current query */
- int normalMode; /* Output mode before ".explain on" */
- int writableSchema; /* True if PRAGMA writable_schema=ON */
- int showHeader; /* True to show column names in List or Column mode */
- int nCheck; /* Number of ".check" commands run */
- unsigned shellFlgs; /* Various flags */
- char *zDestTable; /* Name of destination table when MODE_Insert */
- char zTestcase[30]; /* Name of current test case */
- char colSeparator[20]; /* Column separator character for several modes */
- char rowSeparator[20]; /* Row separator character for MODE_Ascii */
- int colWidth[100]; /* Requested width of each column when in column mode*/
- int actualWidth[100]; /* Actual width of each column */
- char nullValue[20]; /* The text to print when a NULL comes back from
- ** the database */
- char outfile[FILENAME_MAX]; /* Filename for *out */
- const char *zDbFilename; /* name of the database file */
- char *zFreeOnClose; /* Filename to free when closing */
- const char *zVfs; /* Name of VFS to use */
- sqlite3_stmt *pStmt; /* Current statement if any. */
- FILE *pLog; /* Write log output here */
- int *aiIndent; /* Array of indents used in MODE_Explain */
- int nIndent; /* Size of array aiIndent[] */
- int iIndent; /* Index of current op in aiIndent[] */
-#if defined(SQLITE_ENABLE_SESSION)
- int nSession; /* Number of active sessions */
- OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */
-#endif
-};
-
-/*
-** These are the allowed shellFlgs values
-*/
-#define SHFLG_Scratch 0x00000001 /* The --scratch option is used */
-#define SHFLG_Pagecache 0x00000002 /* The --pagecache option is used */
-#define SHFLG_Lookaside 0x00000004 /* Lookaside memory is used */
-#define SHFLG_Backslash 0x00000008 /* The --backslash option is used */
-#define SHFLG_PreserveRowid 0x00000010 /* .dump preserves rowid values */
-#define SHFLG_Newlines 0x00000020 /* .dump --newline flag */
-#define SHFLG_CountChanges 0x00000040 /* .changes setting */
-#define SHFLG_Echo 0x00000080 /* .echo or --echo setting */
-
-/*
-** Macros for testing and setting shellFlgs
-*/
-#define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0)
-#define ShellSetFlag(P,X) ((P)->shellFlgs|=(X))
-#define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X)))
-
-/*
-** These are the allowed modes.
-*/
-#define MODE_Line 0 /* One column per line. Blank line between records */
-#define MODE_Column 1 /* One record per line in neat columns */
-#define MODE_List 2 /* One record per line with a separator */
-#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
-#define MODE_Html 4 /* Generate an XHTML table */
-#define MODE_Insert 5 /* Generate SQL "insert" statements */
-#define MODE_Quote 6 /* Quote values as for SQL */
-#define MODE_Tcl 7 /* Generate ANSI-C or TCL quoted elements */
-#define MODE_Csv 8 /* Quote strings, numbers are plain */
-#define MODE_Explain 9 /* Like MODE_Column, but do not truncate data */
-#define MODE_Ascii 10 /* Use ASCII unit and record separators (0x1F/0x1E) */
-#define MODE_Pretty 11 /* Pretty-print schemas */
-
-static const char *modeDescr[] = {
- "line",
- "column",
- "list",
- "semi",
- "html",
- "insert",
- "quote",
- "tcl",
- "csv",
- "explain",
- "ascii",
- "prettyprint",
-};
-
-/*
-** These are the column/row/line separators used by the various
-** import/export modes.
-*/
-#define SEP_Column "|"
-#define SEP_Row "\n"
-#define SEP_Tab "\t"
-#define SEP_Space " "
-#define SEP_Comma ","
-#define SEP_CrLf "\r\n"
-#define SEP_Unit "\x1F"
-#define SEP_Record "\x1E"
-
-/*
-** Number of elements in an array
-*/
-#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
-
-/*
-** A callback for the sqlite3_log() interface.
-*/
-static void shellLog(void *pArg, int iErrCode, const char *zMsg){
- ShellState *p = (ShellState*)pArg;
- if( p->pLog==0 ) return;
- utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
- fflush(p->pLog);
-}
-
-/*
-** Output the given string as a hex-encoded blob (eg. X'1234' )
-*/
-static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
- int i;
- char *zBlob = (char *)pBlob;
- raw_printf(out,"X'");
- for(i=0; i<nBlob; i++){ raw_printf(out,"%02x",zBlob[i]&0xff); }
- raw_printf(out,"'");
-}
-
-/*
-** Find a string that is not found anywhere in z[]. Return a pointer
-** to that string.
-**
-** Try to use zA and zB first. If both of those are already found in z[]
-** then make up some string and store it in the buffer zBuf.
-*/
-static const char *unused_string(
- const char *z, /* Result must not appear anywhere in z */
- const char *zA, const char *zB, /* Try these first */
- char *zBuf /* Space to store a generated string */
-){
- unsigned i = 0;
- if( strstr(z, zA)==0 ) return zA;
- if( strstr(z, zB)==0 ) return zB;
- do{
- sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
- }while( strstr(z,zBuf)!=0 );
- return zBuf;
-}
-
-/*
-** Output the given string as a quoted string using SQL quoting conventions.
-**
-** See also: output_quoted_escaped_string()
-*/
-static void output_quoted_string(FILE *out, const char *z){
- int i;
- char c;
- setBinaryMode(out, 1);
- for(i=0; (c = z[i])!=0 && c!='\''; i++){}
- if( c==0 ){
- utf8_printf(out,"'%s'",z);
- }else{
- raw_printf(out, "'");
- while( *z ){
- for(i=0; (c = z[i])!=0 && c!='\''; i++){}
- if( c=='\'' ) i++;
- if( i ){
- utf8_printf(out, "%.*s", i, z);
- z += i;
- }
- if( c=='\'' ){
- raw_printf(out, "'");
- continue;
- }
- if( c==0 ){
- break;
- }
- z++;
- }
- raw_printf(out, "'");
- }
- setTextMode(out, 1);
-}
-
-/*
-** Output the given string as a quoted string using SQL quoting conventions.
-** Additionallly , escape the "\n" and "\r" characters so that they do not
-** get corrupted by end-of-line translation facilities in some operating
-** systems.
-**
-** This is like output_quoted_string() but with the addition of the \r\n
-** escape mechanism.
-*/
-static void output_quoted_escaped_string(FILE *out, const char *z){
- int i;
- char c;
- setBinaryMode(out, 1);
- for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
- if( c==0 ){
- utf8_printf(out,"'%s'",z);
- }else{
- const char *zNL = 0;
- const char *zCR = 0;
- int nNL = 0;
- int nCR = 0;
- char zBuf1[20], zBuf2[20];
- for(i=0; z[i]; i++){
- if( z[i]=='\n' ) nNL++;
- if( z[i]=='\r' ) nCR++;
- }
- if( nNL ){
- raw_printf(out, "replace(");
- zNL = unused_string(z, "\\n", "\\012", zBuf1);
- }
- if( nCR ){
- raw_printf(out, "replace(");
- zCR = unused_string(z, "\\r", "\\015", zBuf2);
- }
- raw_printf(out, "'");
- while( *z ){
- for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
- if( c=='\'' ) i++;
- if( i ){
- utf8_printf(out, "%.*s", i, z);
- z += i;
- }
- if( c=='\'' ){
- raw_printf(out, "'");
- continue;
- }
- if( c==0 ){
- break;
- }
- z++;
- if( c=='\n' ){
- raw_printf(out, "%s", zNL);
- continue;
- }
- raw_printf(out, "%s", zCR);
- }
- raw_printf(out, "'");
- if( nCR ){
- raw_printf(out, ",'%s',char(13))", zCR);
- }
- if( nNL ){
- raw_printf(out, ",'%s',char(10))", zNL);
- }
- }
- setTextMode(out, 1);
-}
-
-/*
-** Output the given string as a quoted according to C or TCL quoting rules.
-*/
-static void output_c_string(FILE *out, const char *z){
- unsigned int c;
- fputc('"', out);
- while( (c = *(z++))!=0 ){
- if( c=='\\' ){
- fputc(c, out);
- fputc(c, out);
- }else if( c=='"' ){
- fputc('\\', out);
- fputc('"', out);
- }else if( c=='\t' ){
- fputc('\\', out);
- fputc('t', out);
- }else if( c=='\n' ){
- fputc('\\', out);
- fputc('n', out);
- }else if( c=='\r' ){
- fputc('\\', out);
- fputc('r', out);
- }else if( !isprint(c&0xff) ){
- raw_printf(out, "\\%03o", c&0xff);
- }else{
- fputc(c, out);
- }
- }
- fputc('"', out);
-}
-
-/*
-** Output the given string with characters that are special to
-** HTML escaped.
-*/
-static void output_html_string(FILE *out, const char *z){
- int i;
- if( z==0 ) z = "";
- while( *z ){
- for(i=0; z[i]
- && z[i]!='<'
- && z[i]!='&'
- && z[i]!='>'
- && z[i]!='\"'
- && z[i]!='\'';
- i++){}
- if( i>0 ){
- utf8_printf(out,"%.*s",i,z);
- }
- if( z[i]=='<' ){
- raw_printf(out,"&lt;");
- }else if( z[i]=='&' ){
- raw_printf(out,"&amp;");
- }else if( z[i]=='>' ){
- raw_printf(out,"&gt;");
- }else if( z[i]=='\"' ){
- raw_printf(out,"&quot;");
- }else if( z[i]=='\'' ){
- raw_printf(out,"&#39;");
- }else{
- break;
- }
- z += i + 1;
- }
-}
-
-/*
-** If a field contains any character identified by a 1 in the following
-** array, then the string must be quoted for CSV.
-*/
-static const char needCsvQuote[] = {
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-};
-
-/*
-** Output a single term of CSV. Actually, p->colSeparator is used for
-** the separator, which may or may not be a comma. p->nullValue is
-** the null value. Strings are quoted if necessary. The separator
-** is only issued if bSep is true.
-*/
-static void output_csv(ShellState *p, const char *z, int bSep){
- FILE *out = p->out;
- if( z==0 ){
- utf8_printf(out,"%s",p->nullValue);
- }else{
- int i;
- int nSep = strlen30(p->colSeparator);
- for(i=0; z[i]; i++){
- if( needCsvQuote[((unsigned char*)z)[i]]
- || (z[i]==p->colSeparator[0] &&
- (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
- i = 0;
- break;
- }
- }
- if( i==0 ){
- putc('"', out);
- for(i=0; z[i]; i++){
- if( z[i]=='"' ) putc('"', out);
- putc(z[i], out);
- }
- putc('"', out);
- }else{
- utf8_printf(out, "%s", z);
- }
- }
- if( bSep ){
- utf8_printf(p->out, "%s", p->colSeparator);
- }
-}
-
-#ifdef SIGINT
-/*
-** This routine runs when the user presses Ctrl-C
-*/
-static void interrupt_handler(int NotUsed){
- UNUSED_PARAMETER(NotUsed);
- seenInterrupt++;
- if( seenInterrupt>2 ) exit(1);
- if( globalDb ) sqlite3_interrupt(globalDb);
-}
-#endif
-
-#ifndef SQLITE_OMIT_AUTHORIZATION
-/*
-** When the ".auth ON" is set, the following authorizer callback is
-** invoked. It always returns SQLITE_OK.
-*/
-static int shellAuth(
- void *pClientData,
- int op,
- const char *zA1,
- const char *zA2,
- const char *zA3,
- const char *zA4
-){
- ShellState *p = (ShellState*)pClientData;
- static const char *azAction[] = { 0,
- "CREATE_INDEX", "CREATE_TABLE", "CREATE_TEMP_INDEX",
- "CREATE_TEMP_TABLE", "CREATE_TEMP_TRIGGER", "CREATE_TEMP_VIEW",
- "CREATE_TRIGGER", "CREATE_VIEW", "DELETE",
- "DROP_INDEX", "DROP_TABLE", "DROP_TEMP_INDEX",
- "DROP_TEMP_TABLE", "DROP_TEMP_TRIGGER", "DROP_TEMP_VIEW",
- "DROP_TRIGGER", "DROP_VIEW", "INSERT",
- "PRAGMA", "READ", "SELECT",
- "TRANSACTION", "UPDATE", "ATTACH",
- "DETACH", "ALTER_TABLE", "REINDEX",
- "ANALYZE", "CREATE_VTABLE", "DROP_VTABLE",
- "FUNCTION", "SAVEPOINT", "RECURSIVE"
- };
- int i;
- const char *az[4];
- az[0] = zA1;
- az[1] = zA2;
- az[2] = zA3;
- az[3] = zA4;
- utf8_printf(p->out, "authorizer: %s", azAction[op]);
- for(i=0; i<4; i++){
- raw_printf(p->out, " ");
- if( az[i] ){
- output_c_string(p->out, az[i]);
- }else{
- raw_printf(p->out, "NULL");
- }
- }
- raw_printf(p->out, "\n");
- return SQLITE_OK;
-}
-#endif
-
-/*
-** Print a schema statement. Part of MODE_Semi and MODE_Pretty output.
-**
-** This routine converts some CREATE TABLE statements for shadow tables
-** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements.
-*/
-static void printSchemaLine(FILE *out, const char *z, const char *zTail){
- if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
- utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
- }else{
- utf8_printf(out, "%s%s", z, zTail);
- }
-}
-static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
- char c = z[n];
- z[n] = 0;
- printSchemaLine(out, z, zTail);
- z[n] = c;
-}
-
-/*
-** This is the callback routine that the shell
-** invokes for each row of a query result.
-*/
-static int shell_callback(
- void *pArg,
- int nArg, /* Number of result columns */
- char **azArg, /* Text of each result column */
- char **azCol, /* Column names */
- int *aiType /* Column types */
-){
- int i;
- ShellState *p = (ShellState*)pArg;
-
- switch( p->cMode ){
- case MODE_Line: {
- int w = 5;
- if( azArg==0 ) break;
- for(i=0; i<nArg; i++){
- int len = strlen30(azCol[i] ? azCol[i] : "");
- if( len>w ) w = len;
- }
- if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator);
- for(i=0; i<nArg; i++){
- utf8_printf(p->out,"%*s = %s%s", w, azCol[i],
- azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
- }
- break;
- }
- case MODE_Explain:
- case MODE_Column: {
- static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
- const int *colWidth;
- int showHdr;
- char *rowSep;
- if( p->cMode==MODE_Column ){
- colWidth = p->colWidth;
- showHdr = p->showHeader;
- rowSep = p->rowSeparator;
- }else{
- colWidth = aExplainWidths;
- showHdr = 1;
- rowSep = SEP_Row;
- }
- if( p->cnt++==0 ){
- for(i=0; i<nArg; i++){
- int w, n;
- if( i<ArraySize(p->colWidth) ){
- w = colWidth[i];
- }else{
- w = 0;
- }
- if( w==0 ){
- w = strlenChar(azCol[i] ? azCol[i] : "");
- if( w<10 ) w = 10;
- n = strlenChar(azArg && azArg[i] ? azArg[i] : p->nullValue);
- if( w<n ) w = n;
- }
- if( i<ArraySize(p->actualWidth) ){
- p->actualWidth[i] = w;
- }
- if( showHdr ){
- utf8_width_print(p->out, w, azCol[i]);
- utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
- }
- }
- if( showHdr ){
- for(i=0; i<nArg; i++){
- int w;
- if( i<ArraySize(p->actualWidth) ){
- w = p->actualWidth[i];
- if( w<0 ) w = -w;
- }else{
- w = 10;
- }
- utf8_printf(p->out,"%-*.*s%s",w,w,
- "----------------------------------------------------------"
- "----------------------------------------------------------",
- i==nArg-1 ? rowSep : " ");
- }
- }
- }
- if( azArg==0 ) break;
- for(i=0; i<nArg; i++){
- int w;
- if( i<ArraySize(p->actualWidth) ){
- w = p->actualWidth[i];
- }else{
- w = 10;
- }
- if( p->cMode==MODE_Explain && azArg[i] && strlenChar(azArg[i])>w ){
- w = strlenChar(azArg[i]);
- }
- if( i==1 && p->aiIndent && p->pStmt ){
- if( p->iIndent<p->nIndent ){
- utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
- }
- p->iIndent++;
- }
- utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
- utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " ");
- }
- break;
- }
- case MODE_Semi: { /* .schema and .fullschema output */
- printSchemaLine(p->out, azArg[0], ";\n");
- break;
- }
- case MODE_Pretty: { /* .schema and .fullschema with --indent */
- char *z;
- int j;
- int nParen = 0;
- char cEnd = 0;
- char c;
- int nLine = 0;
- assert( nArg==1 );
- if( azArg[0]==0 ) break;
- if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
- || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
- ){
- utf8_printf(p->out, "%s;\n", azArg[0]);
- break;
- }
- z = sqlite3_mprintf("%s", azArg[0]);
- j = 0;
- for(i=0; IsSpace(z[i]); i++){}
- for(; (c = z[i])!=0; i++){
- if( IsSpace(c) ){
- if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
- }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
- j--;
- }
- z[j++] = c;
- }
- while( j>0 && IsSpace(z[j-1]) ){ j--; }
- z[j] = 0;
- if( strlen30(z)>=79 ){
- for(i=j=0; (c = z[i])!=0; i++){
- if( c==cEnd ){
- cEnd = 0;
- }else if( c=='"' || c=='\'' || c=='`' ){
- cEnd = c;
- }else if( c=='[' ){
- cEnd = ']';
- }else if( c=='(' ){
- nParen++;
- }else if( c==')' ){
- nParen--;
- if( nLine>0 && nParen==0 && j>0 ){
- printSchemaLineN(p->out, z, j, "\n");
- j = 0;
- }
- }
- z[j++] = c;
- if( nParen==1 && (c=='(' || c==',' || c=='\n') ){
- if( c=='\n' ) j--;
- printSchemaLineN(p->out, z, j, "\n ");
- j = 0;
- nLine++;
- while( IsSpace(z[i+1]) ){ i++; }
- }
- }
- z[j] = 0;
- }
- printSchemaLine(p->out, z, ";\n");
- sqlite3_free(z);
- break;
- }
- case MODE_List: {
- if( p->cnt++==0 && p->showHeader ){
- for(i=0; i<nArg; i++){
- utf8_printf(p->out,"%s%s",azCol[i],
- i==nArg-1 ? p->rowSeparator : p->colSeparator);
- }
- }
- if( azArg==0 ) break;
- for(i=0; i<nArg; i++){
- char *z = azArg[i];
- if( z==0 ) z = p->nullValue;
- utf8_printf(p->out, "%s", z);
- if( i<nArg-1 ){
- utf8_printf(p->out, "%s", p->colSeparator);
- }else{
- utf8_printf(p->out, "%s", p->rowSeparator);
- }
- }
- break;
- }
- case MODE_Html: {
- if( p->cnt++==0 && p->showHeader ){
- raw_printf(p->out,"<TR>");
- for(i=0; i<nArg; i++){
- raw_printf(p->out,"<TH>");
- output_html_string(p->out, azCol[i]);
- raw_printf(p->out,"</TH>\n");
- }
- raw_printf(p->out,"</TR>\n");
- }
- if( azArg==0 ) break;
- raw_printf(p->out,"<TR>");
- for(i=0; i<nArg; i++){
- raw_printf(p->out,"<TD>");
- output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
- raw_printf(p->out,"</TD>\n");
- }
- raw_printf(p->out,"</TR>\n");
- break;
- }
- case MODE_Tcl: {
- if( p->cnt++==0 && p->showHeader ){
- for(i=0; i<nArg; i++){
- output_c_string(p->out,azCol[i] ? azCol[i] : "");
- if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
- }
- utf8_printf(p->out, "%s", p->rowSeparator);
- }
- if( azArg==0 ) break;
- for(i=0; i<nArg; i++){
- output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
- if(i<nArg-1) utf8_printf(p->out, "%s", p->colSeparator);
- }
- utf8_printf(p->out, "%s", p->rowSeparator);
- break;
- }
- case MODE_Csv: {
- setBinaryMode(p->out, 1);
- if( p->cnt++==0 && p->showHeader ){
- for(i=0; i<nArg; i++){
- output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
- }
- utf8_printf(p->out, "%s", p->rowSeparator);
- }
- if( nArg>0 ){
- for(i=0; i<nArg; i++){
- output_csv(p, azArg[i], i<nArg-1);
- }
- utf8_printf(p->out, "%s", p->rowSeparator);
- }
- setTextMode(p->out, 1);
- break;
- }
- case MODE_Insert: {
- if( azArg==0 ) break;
- utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
- if( p->showHeader ){
- raw_printf(p->out,"(");
- for(i=0; i<nArg; i++){
- if( i>0 ) raw_printf(p->out, ",");
- if( quoteChar(azCol[i]) ){
- char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
- utf8_printf(p->out, "%s", z);
- sqlite3_free(z);
- }else{
- raw_printf(p->out, "%s", azCol[i]);
- }
- }
- raw_printf(p->out,")");
- }
- p->cnt++;
- for(i=0; i<nArg; i++){
- raw_printf(p->out, i>0 ? "," : " VALUES(");
- if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- utf8_printf(p->out,"NULL");
- }else if( aiType && aiType[i]==SQLITE_TEXT ){
- if( ShellHasFlag(p, SHFLG_Newlines) ){
- output_quoted_string(p->out, azArg[i]);
- }else{
- output_quoted_escaped_string(p->out, azArg[i]);
- }
- }else if( aiType && aiType[i]==SQLITE_INTEGER ){
- utf8_printf(p->out,"%s", azArg[i]);
- }else if( aiType && aiType[i]==SQLITE_FLOAT ){
- char z[50];
- double r = sqlite3_column_double(p->pStmt, i);
- sqlite3_snprintf(50,z,"%!.20g", r);
- raw_printf(p->out, "%s", z);
- }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
- const void *pBlob = sqlite3_column_blob(p->pStmt, i);
- int nBlob = sqlite3_column_bytes(p->pStmt, i);
- output_hex_blob(p->out, pBlob, nBlob);
- }else if( isNumber(azArg[i], 0) ){
- utf8_printf(p->out,"%s", azArg[i]);
- }else if( ShellHasFlag(p, SHFLG_Newlines) ){
- output_quoted_string(p->out, azArg[i]);
- }else{
- output_quoted_escaped_string(p->out, azArg[i]);
- }
- }
- raw_printf(p->out,");\n");
- break;
- }
- case MODE_Quote: {
- if( azArg==0 ) break;
- if( p->cnt==0 && p->showHeader ){
- for(i=0; i<nArg; i++){
- if( i>0 ) raw_printf(p->out, ",");
- output_quoted_string(p->out, azCol[i]);
- }
- raw_printf(p->out,"\n");
- }
- p->cnt++;
- for(i=0; i<nArg; i++){
- if( i>0 ) raw_printf(p->out, ",");
- if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- utf8_printf(p->out,"NULL");
- }else if( aiType && aiType[i]==SQLITE_TEXT ){
- output_quoted_string(p->out, azArg[i]);
- }else if( aiType && aiType[i]==SQLITE_INTEGER ){
- utf8_printf(p->out,"%s", azArg[i]);
- }else if( aiType && aiType[i]==SQLITE_FLOAT ){
- char z[50];
- double r = sqlite3_column_double(p->pStmt, i);
- sqlite3_snprintf(50,z,"%!.20g", r);
- raw_printf(p->out, "%s", z);
- }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
- const void *pBlob = sqlite3_column_blob(p->pStmt, i);
- int nBlob = sqlite3_column_bytes(p->pStmt, i);
- output_hex_blob(p->out, pBlob, nBlob);
- }else if( isNumber(azArg[i], 0) ){
- utf8_printf(p->out,"%s", azArg[i]);
- }else{
- output_quoted_string(p->out, azArg[i]);
- }
- }
- raw_printf(p->out,"\n");
- break;
- }
- case MODE_Ascii: {
- if( p->cnt++==0 && p->showHeader ){
- for(i=0; i<nArg; i++){
- if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
- utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : "");
- }
- utf8_printf(p->out, "%s", p->rowSeparator);
- }
- if( azArg==0 ) break;
- for(i=0; i<nArg; i++){
- if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
- utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
- }
- utf8_printf(p->out, "%s", p->rowSeparator);
- break;
- }
- }
- return 0;
-}
-
-/*
-** This is the callback routine that the SQLite library
-** invokes for each row of a query result.
-*/
-static int callback(void *pArg, int nArg, char **azArg, char **azCol){
- /* since we don't have type info, call the shell_callback with a NULL value */
- return shell_callback(pArg, nArg, azArg, azCol, NULL);
-}
-
-/*
-** This is the callback routine from sqlite3_exec() that appends all
-** output onto the end of a ShellText object.
-*/
-static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){
- ShellText *p = (ShellText*)pArg;
- int i;
- UNUSED_PARAMETER(az);
- if( p->n ) appendText(p, "|", 0);
- for(i=0; i<nArg; i++){
- if( i ) appendText(p, ",", 0);
- if( azArg[i] ) appendText(p, azArg[i], 0);
- }
- return 0;
-}
-
-/*
-** Generate an appropriate SELFTEST table in the main database.
-*/
-static void createSelftestTable(ShellState *p){
- char *zErrMsg = 0;
- sqlite3_exec(p->db,
- "SAVEPOINT selftest_init;\n"
- "CREATE TABLE IF NOT EXISTS selftest(\n"
- " tno INTEGER PRIMARY KEY,\n" /* Test number */
- " op TEXT,\n" /* Operator: memo run */
- " cmd TEXT,\n" /* Command text */
- " ans TEXT\n" /* Desired answer */
- ");"
- "CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n"
- "INSERT INTO [_shell$self](rowid,op,cmd)\n"
- " VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n"
- " 'memo','Tests generated by --init');\n"
- "INSERT INTO [_shell$self]\n"
- " SELECT 'run',\n"
- " 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql "
- "FROM sqlite_master ORDER BY 2'',224))',\n"
- " hex(sha3_query('SELECT type,name,tbl_name,sql "
- "FROM sqlite_master ORDER BY 2',224));\n"
- "INSERT INTO [_shell$self]\n"
- " SELECT 'run',"
- " 'SELECT hex(sha3_query(''SELECT * FROM \"' ||"
- " printf('%w',name) || '\" NOT INDEXED'',224))',\n"
- " hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n"
- " FROM (\n"
- " SELECT name FROM sqlite_master\n"
- " WHERE type='table'\n"
- " AND name<>'selftest'\n"
- " AND coalesce(rootpage,0)>0\n"
- " )\n"
- " ORDER BY name;\n"
- "INSERT INTO [_shell$self]\n"
- " VALUES('run','PRAGMA integrity_check','ok');\n"
- "INSERT INTO selftest(tno,op,cmd,ans)"
- " SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n"
- "DROP TABLE [_shell$self];"
- ,0,0,&zErrMsg);
- if( zErrMsg ){
- utf8_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
- sqlite3_free(zErrMsg);
- }
- sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
-}
-
-
-/*
-** Set the destination table field of the ShellState structure to
-** the name of the table given. Escape any quote characters in the
-** table name.
-*/
-static void set_table_name(ShellState *p, const char *zName){
- int i, n;
- int cQuote;
- char *z;
-
- if( p->zDestTable ){
- free(p->zDestTable);
- p->zDestTable = 0;
- }
- if( zName==0 ) return;
- cQuote = quoteChar(zName);
- n = strlen30(zName);
- if( cQuote ) n += n+2;
- z = p->zDestTable = malloc( n+1 );
- if( z==0 ){
- raw_printf(stderr,"Error: out of memory\n");
- exit(1);
- }
- n = 0;
- if( cQuote ) z[n++] = cQuote;
- for(i=0; zName[i]; i++){
- z[n++] = zName[i];
- if( zName[i]==cQuote ) z[n++] = cQuote;
- }
- if( cQuote ) z[n++] = cQuote;
- z[n] = 0;
-}
-
-
-/*
-** Execute a query statement that will generate SQL output. Print
-** the result columns, comma-separated, on a line and then add a
-** semicolon terminator to the end of that line.
-**
-** If the number of columns is 1 and that column contains text "--"
-** then write the semicolon on a separate line. That way, if a
-** "--" comment occurs at the end of the statement, the comment
-** won't consume the semicolon terminator.
-*/
-static int run_table_dump_query(
- ShellState *p, /* Query context */
- const char *zSelect, /* SELECT statement to extract content */
- const char *zFirstRow /* Print before first row, if not NULL */
-){
- sqlite3_stmt *pSelect;
- int rc;
- int nResult;
- int i;
- const char *z;
- rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
- if( rc!=SQLITE_OK || !pSelect ){
- utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
- sqlite3_errmsg(p->db));
- if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
- return rc;
- }
- rc = sqlite3_step(pSelect);
- nResult = sqlite3_column_count(pSelect);
- while( rc==SQLITE_ROW ){
- if( zFirstRow ){
- utf8_printf(p->out, "%s", zFirstRow);
- zFirstRow = 0;
- }
- z = (const char*)sqlite3_column_text(pSelect, 0);
- utf8_printf(p->out, "%s", z);
- for(i=1; i<nResult; i++){
- utf8_printf(p->out, ",%s", sqlite3_column_text(pSelect, i));
- }
- if( z==0 ) z = "";
- while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
- if( z[0] ){
- raw_printf(p->out, "\n;\n");
- }else{
- raw_printf(p->out, ";\n");
- }
- rc = sqlite3_step(pSelect);
- }
- rc = sqlite3_finalize(pSelect);
- if( rc!=SQLITE_OK ){
- utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc,
- sqlite3_errmsg(p->db));
- if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
- }
- return rc;
-}
-
-/*
-** Allocate space and save off current error string.
-*/
-static char *save_err_msg(
- sqlite3 *db /* Database to query */
-){
- int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
- char *zErrMsg = sqlite3_malloc64(nErrMsg);
- if( zErrMsg ){
- memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
- }
- return zErrMsg;
-}
-
-#ifdef __linux__
-/*
-** Attempt to display I/O stats on Linux using /proc/PID/io
-*/
-static void displayLinuxIoStats(FILE *out){
- FILE *in;
- char z[200];
- sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
- in = fopen(z, "rb");
- if( in==0 ) return;
- while( fgets(z, sizeof(z), in)!=0 ){
- static const struct {
- const char *zPattern;
- const char *zDesc;
- } aTrans[] = {
- { "rchar: ", "Bytes received by read():" },
- { "wchar: ", "Bytes sent to write():" },
- { "syscr: ", "Read() system calls:" },
- { "syscw: ", "Write() system calls:" },
- { "read_bytes: ", "Bytes read from storage:" },
- { "write_bytes: ", "Bytes written to storage:" },
- { "cancelled_write_bytes: ", "Cancelled write bytes:" },
- };
- int i;
- for(i=0; i<ArraySize(aTrans); i++){
- int n = (int)strlen(aTrans[i].zPattern);
- if( strncmp(aTrans[i].zPattern, z, n)==0 ){
- utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
- break;
- }
- }
- }
- fclose(in);
-}
-#endif
-
-/*
-** Display a single line of status using 64-bit values.
-*/
-static void displayStatLine(
- ShellState *p, /* The shell context */
- char *zLabel, /* Label for this one line */
- char *zFormat, /* Format for the result */
- int iStatusCtrl, /* Which status to display */
- int bReset /* True to reset the stats */
-){
- sqlite3_int64 iCur = -1;
- sqlite3_int64 iHiwtr = -1;
- int i, nPercent;
- char zLine[200];
- sqlite3_status64(iStatusCtrl, &iCur, &iHiwtr, bReset);
- for(i=0, nPercent=0; zFormat[i]; i++){
- if( zFormat[i]=='%' ) nPercent++;
- }
- if( nPercent>1 ){
- sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr);
- }else{
- sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
- }
- raw_printf(p->out, "%-36s %s\n", zLabel, zLine);
-}
-
-/*
-** Display memory stats.
-*/
-static int display_stats(
- sqlite3 *db, /* Database to query */
- ShellState *pArg, /* Pointer to ShellState */
- int bReset /* True to reset the stats */
-){
- int iCur;
- int iHiwtr;
-
- if( pArg && pArg->out ){
- displayStatLine(pArg, "Memory Used:",
- "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
- displayStatLine(pArg, "Number of Outstanding Allocations:",
- "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
- if( pArg->shellFlgs & SHFLG_Pagecache ){
- displayStatLine(pArg, "Number of Pcache Pages Used:",
- "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
- }
- displayStatLine(pArg, "Number of Pcache Overflow Bytes:",
- "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
- if( pArg->shellFlgs & SHFLG_Scratch ){
- displayStatLine(pArg, "Number of Scratch Allocations Used:",
- "%lld (max %lld)", SQLITE_STATUS_SCRATCH_USED, bReset);
- }
- displayStatLine(pArg, "Number of Scratch Overflow Bytes:",
- "%lld (max %lld) bytes", SQLITE_STATUS_SCRATCH_OVERFLOW, bReset);
- displayStatLine(pArg, "Largest Allocation:",
- "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
- displayStatLine(pArg, "Largest Pcache Allocation:",
- "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
- displayStatLine(pArg, "Largest Scratch Allocation:",
- "%lld bytes", SQLITE_STATUS_SCRATCH_SIZE, bReset);
-#ifdef YYTRACKMAXSTACKDEPTH
- displayStatLine(pArg, "Deepest Parser Stack:",
- "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
-#endif
- }
-
- if( pArg && pArg->out && db ){
- if( pArg->shellFlgs & SHFLG_Lookaside ){
- iHiwtr = iCur = -1;
- sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
- &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out,
- "Lookaside Slots Used: %d (max %d)\n",
- iCur, iHiwtr);
- sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
- &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Successful lookaside attempts: %d\n",
- iHiwtr);
- sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
- &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Lookaside failures due to size: %d\n",
- iHiwtr);
- sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
- &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Lookaside failures due to OOM: %d\n",
- iHiwtr);
- }
- iHiwtr = iCur = -1;
- sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Pager Heap Usage: %d bytes\n",
- iCur);
- iHiwtr = iCur = -1;
- sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
- raw_printf(pArg->out, "Page cache hits: %d\n", iCur);
- iHiwtr = iCur = -1;
- sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
- raw_printf(pArg->out, "Page cache misses: %d\n", iCur);
- iHiwtr = iCur = -1;
- sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
- raw_printf(pArg->out, "Page cache writes: %d\n", iCur);
- iHiwtr = iCur = -1;
- sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Schema Heap Usage: %d bytes\n",
- iCur);
- iHiwtr = iCur = -1;
- sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n",
- iCur);
- }
-
- if( pArg && pArg->out && db && pArg->pStmt ){
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
- bReset);
- raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur);
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
- raw_printf(pArg->out, "Sort Operations: %d\n", iCur);
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
- raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur);
- iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
- raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
- }
-
-#ifdef __linux__
- displayLinuxIoStats(pArg->out);
-#endif
-
- /* Do not remove this machine readable comment: extra-stats-output-here */
-
- return 0;
-}
-
-/*
-** Display scan stats.
-*/
-static void display_scanstats(
- sqlite3 *db, /* Database to query */
- ShellState *pArg /* Pointer to ShellState */
-){
-#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
- UNUSED_PARAMETER(db);
- UNUSED_PARAMETER(pArg);
-#else
- int i, k, n, mx;
- raw_printf(pArg->out, "-------- scanstats --------\n");
- mx = 0;
- for(k=0; k<=mx; k++){
- double rEstLoop = 1.0;
- for(i=n=0; 1; i++){
- sqlite3_stmt *p = pArg->pStmt;
- sqlite3_int64 nLoop, nVisit;
- double rEst;
- int iSid;
- const char *zExplain;
- if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){
- break;
- }
- sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid);
- if( iSid>mx ) mx = iSid;
- if( iSid!=k ) continue;
- if( n==0 ){
- rEstLoop = (double)nLoop;
- if( k>0 ) raw_printf(pArg->out, "-------- subquery %d -------\n", k);
- }
- n++;
- sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
- sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst);
- sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
- utf8_printf(pArg->out, "Loop %2d: %s\n", n, zExplain);
- rEstLoop *= rEst;
- raw_printf(pArg->out,
- " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
- nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
- );
- }
- }
- raw_printf(pArg->out, "---------------------------\n");
-#endif
-}
-
-/*
-** Parameter azArray points to a zero-terminated array of strings. zStr
-** points to a single nul-terminated string. Return non-zero if zStr
-** is equal, according to strcmp(), to any of the strings in the array.
-** Otherwise, return zero.
-*/
-static int str_in_array(const char *zStr, const char **azArray){
- int i;
- for(i=0; azArray[i]; i++){
- if( 0==strcmp(zStr, azArray[i]) ) return 1;
- }
- return 0;
-}
-
-/*
-** If compiled statement pSql appears to be an EXPLAIN statement, allocate
-** and populate the ShellState.aiIndent[] array with the number of
-** spaces each opcode should be indented before it is output.
-**
-** The indenting rules are:
-**
-** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
-** all opcodes that occur between the p2 jump destination and the opcode
-** itself by 2 spaces.
-**
-** * For each "Goto", if the jump destination is earlier in the program
-** and ends on one of:
-** Yield SeekGt SeekLt RowSetRead Rewind
-** or if the P1 parameter is one instead of zero,
-** then indent all opcodes between the earlier instruction
-** and "Goto" by 2 spaces.
-*/
-static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
- const char *zSql; /* The text of the SQL statement */
- const char *z; /* Used to check if this is an EXPLAIN */
- int *abYield = 0; /* True if op is an OP_Yield */
- int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
- int iOp; /* Index of operation in p->aiIndent[] */
-
- const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
- "NextIfOpen", "PrevIfOpen", 0 };
- const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
- "Rewind", 0 };
- const char *azGoto[] = { "Goto", 0 };
-
- /* Try to figure out if this is really an EXPLAIN statement. If this
- ** cannot be verified, return early. */
- if( sqlite3_column_count(pSql)!=8 ){
- p->cMode = p->mode;
- return;
- }
- zSql = sqlite3_sql(pSql);
- if( zSql==0 ) return;
- for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
- if( sqlite3_strnicmp(z, "explain", 7) ){
- p->cMode = p->mode;
- return;
- }
-
- for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
- int i;
- int iAddr = sqlite3_column_int(pSql, 0);
- const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
-
- /* Set p2 to the P2 field of the current opcode. Then, assuming that
- ** p2 is an instruction address, set variable p2op to the index of that
- ** instruction in the aiIndent[] array. p2 and p2op may be different if
- ** the current instruction is part of a sub-program generated by an
- ** SQL trigger or foreign key. */
- int p2 = sqlite3_column_int(pSql, 3);
- int p2op = (p2 + (iOp-iAddr));
-
- /* Grow the p->aiIndent array as required */
- if( iOp>=nAlloc ){
- if( iOp==0 ){
- /* Do further verfication that this is explain output. Abort if
- ** it is not */
- static const char *explainCols[] = {
- "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
- int jj;
- for(jj=0; jj<ArraySize(explainCols); jj++){
- if( strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
- p->cMode = p->mode;
- sqlite3_reset(pSql);
- return;
- }
- }
- }
- nAlloc += 100;
- p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
- abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
- }
- abYield[iOp] = str_in_array(zOp, azYield);
- p->aiIndent[iOp] = 0;
- p->nIndent = iOp+1;
-
- if( str_in_array(zOp, azNext) ){
- for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
- }
- if( str_in_array(zOp, azGoto) && p2op<p->nIndent
- && (abYield[p2op] || sqlite3_column_int(pSql, 2))
- ){
- for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
- }
- }
-
- p->iIndent = 0;
- sqlite3_free(abYield);
- sqlite3_reset(pSql);
-}
-
-/*
-** Free the array allocated by explain_data_prepare().
-*/
-static void explain_data_delete(ShellState *p){
- sqlite3_free(p->aiIndent);
- p->aiIndent = 0;
- p->nIndent = 0;
- p->iIndent = 0;
-}
-
-/*
-** Disable and restore .wheretrace and .selecttrace settings.
-*/
-#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
-extern int sqlite3SelectTrace;
-static int savedSelectTrace;
-#endif
-#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
-extern int sqlite3WhereTrace;
-static int savedWhereTrace;
-#endif
-static void disable_debug_trace_modes(void){
-#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
- savedSelectTrace = sqlite3SelectTrace;
- sqlite3SelectTrace = 0;
-#endif
-#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
- savedWhereTrace = sqlite3WhereTrace;
- sqlite3WhereTrace = 0;
-#endif
-}
-static void restore_debug_trace_modes(void){
-#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
- sqlite3SelectTrace = savedSelectTrace;
-#endif
-#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
- sqlite3WhereTrace = savedWhereTrace;
-#endif
-}
-
-/*
-** Run a prepared statement
-*/
-static void exec_prepared_stmt(
- ShellState *pArg, /* Pointer to ShellState */
- sqlite3_stmt *pStmt, /* Statment to run */
- int (*xCallback)(void*,int,char**,char**,int*) /* Callback function */
-){
- int rc;
-
- /* perform the first step. this will tell us if we
- ** have a result set or not and how wide it is.
- */
- rc = sqlite3_step(pStmt);
- /* if we have a result set... */
- if( SQLITE_ROW == rc ){
- /* if we have a callback... */
- if( xCallback ){
- /* allocate space for col name ptr, value ptr, and type */
- int nCol = sqlite3_column_count(pStmt);
- void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
- if( !pData ){
- rc = SQLITE_NOMEM;
- }else{
- char **azCols = (char **)pData; /* Names of result columns */
- char **azVals = &azCols[nCol]; /* Results */
- int *aiTypes = (int *)&azVals[nCol]; /* Result types */
- int i, x;
- assert(sizeof(int) <= sizeof(char *));
- /* save off ptrs to column names */
- for(i=0; i<nCol; i++){
- azCols[i] = (char *)sqlite3_column_name(pStmt, i);
- }
- do{
- /* extract the data and data types */
- for(i=0; i<nCol; i++){
- aiTypes[i] = x = sqlite3_column_type(pStmt, i);
- if( x==SQLITE_BLOB && pArg && pArg->cMode==MODE_Insert ){
- azVals[i] = "";
- }else{
- azVals[i] = (char*)sqlite3_column_text(pStmt, i);
- }
- if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
- rc = SQLITE_NOMEM;
- break; /* from for */
- }
- } /* end for */
-
- /* if data and types extracted successfully... */
- if( SQLITE_ROW == rc ){
- /* call the supplied callback with the result row data */
- if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
- rc = SQLITE_ABORT;
- }else{
- rc = sqlite3_step(pStmt);
- }
- }
- } while( SQLITE_ROW == rc );
- sqlite3_free(pData);
- }
- }else{
- do{
- rc = sqlite3_step(pStmt);
- } while( rc == SQLITE_ROW );
- }
- }
-}
-
-/*
-** Execute a statement or set of statements. Print
-** any result rows/columns depending on the current mode
-** set via the supplied callback.
-**
-** This is very similar to SQLite's built-in sqlite3_exec()
-** function except it takes a slightly different callback
-** and callback data argument.
-*/
-static int shell_exec(
- sqlite3 *db, /* An open database */
- const char *zSql, /* SQL to be evaluated */
- int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */
- /* (not the same as sqlite3_exec) */
- ShellState *pArg, /* Pointer to ShellState */
- char **pzErrMsg /* Error msg written here */
-){
- sqlite3_stmt *pStmt = NULL; /* Statement to execute. */
- int rc = SQLITE_OK; /* Return Code */
- int rc2;
- const char *zLeftover; /* Tail of unprocessed SQL */
-
- if( pzErrMsg ){
- *pzErrMsg = NULL;
- }
-
- while( zSql[0] && (SQLITE_OK == rc) ){
- static const char *zStmtSql;
- rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
- if( SQLITE_OK != rc ){
- if( pzErrMsg ){
- *pzErrMsg = save_err_msg(db);
- }
- }else{
- if( !pStmt ){
- /* this happens for a comment or white-space */
- zSql = zLeftover;
- while( IsSpace(zSql[0]) ) zSql++;
- continue;
- }
- zStmtSql = sqlite3_sql(pStmt);
- if( zStmtSql==0 ) zStmtSql = "";
- while( IsSpace(zStmtSql[0]) ) zStmtSql++;
-
- /* save off the prepared statment handle and reset row count */
- if( pArg ){
- pArg->pStmt = pStmt;
- pArg->cnt = 0;
- }
-
- /* echo the sql statement if echo on */
- if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){
- utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
- }
-
- /* Show the EXPLAIN QUERY PLAN if .eqp is on */
- if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){
- sqlite3_stmt *pExplain;
- char *zEQP;
- disable_debug_trace_modes();
- zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
- rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
- if( rc==SQLITE_OK ){
- while( sqlite3_step(pExplain)==SQLITE_ROW ){
- raw_printf(pArg->out,"--EQP-- %d,",sqlite3_column_int(pExplain, 0));
- raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
- raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
- utf8_printf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
- }
- }
- sqlite3_finalize(pExplain);
- sqlite3_free(zEQP);
- if( pArg->autoEQP>=2 ){
- /* Also do an EXPLAIN for ".eqp full" mode */
- zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
- rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
- if( rc==SQLITE_OK ){
- pArg->cMode = MODE_Explain;
- explain_data_prepare(pArg, pExplain);
- exec_prepared_stmt(pArg, pExplain, xCallback);
- explain_data_delete(pArg);
- }
- sqlite3_finalize(pExplain);
- sqlite3_free(zEQP);
- }
- restore_debug_trace_modes();
- }
-
- if( pArg ){
- pArg->cMode = pArg->mode;
- if( pArg->autoExplain
- && sqlite3_column_count(pStmt)==8
- && sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0
- ){
- pArg->cMode = MODE_Explain;
- }
-
- /* If the shell is currently in ".explain" mode, gather the extra
- ** data required to add indents to the output.*/
- if( pArg->cMode==MODE_Explain ){
- explain_data_prepare(pArg, pStmt);
- }
- }
-
- exec_prepared_stmt(pArg, pStmt, xCallback);
- explain_data_delete(pArg);
-
- /* print usage stats if stats on */
- if( pArg && pArg->statsOn ){
- display_stats(db, pArg, 0);
- }
-
- /* print loop-counters if required */
- if( pArg && pArg->scanstatsOn ){
- display_scanstats(db, pArg);
- }
-
- /* Finalize the statement just executed. If this fails, save a
- ** copy of the error message. Otherwise, set zSql to point to the
- ** next statement to execute. */
- rc2 = sqlite3_finalize(pStmt);
- if( rc!=SQLITE_NOMEM ) rc = rc2;
- if( rc==SQLITE_OK ){
- zSql = zLeftover;
- while( IsSpace(zSql[0]) ) zSql++;
- }else if( pzErrMsg ){
- *pzErrMsg = save_err_msg(db);
- }
-
- /* clear saved stmt handle */
- if( pArg ){
- pArg->pStmt = NULL;
- }
- }
- } /* end while */
-
- return rc;
-}
-
-/*
-** Release memory previously allocated by tableColumnList().
-*/
-static void freeColumnList(char **azCol){
- int i;
- for(i=1; azCol[i]; i++){
- sqlite3_free(azCol[i]);
- }
- /* azCol[0] is a static string */
- sqlite3_free(azCol);
-}
-
-/*
-** Return a list of pointers to strings which are the names of all
-** columns in table zTab. The memory to hold the names is dynamically
-** allocated and must be released by the caller using a subsequent call
-** to freeColumnList().
-**
-** The azCol[0] entry is usually NULL. However, if zTab contains a rowid
-** value that needs to be preserved, then azCol[0] is filled in with the
-** name of the rowid column.
-**
-** The first regular column in the table is azCol[1]. The list is terminated
-** by an entry with azCol[i]==0.
-*/
-static char **tableColumnList(ShellState *p, const char *zTab){
- char **azCol = 0;
- sqlite3_stmt *pStmt;
- char *zSql;
- int nCol = 0;
- int nAlloc = 0;
- int nPK = 0; /* Number of PRIMARY KEY columns seen */
- int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */
- int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid);
- int rc;
-
- zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- sqlite3_free(zSql);
- if( rc ) return 0;
- while( sqlite3_step(pStmt)==SQLITE_ROW ){
- if( nCol>=nAlloc-2 ){
- nAlloc = nAlloc*2 + nCol + 10;
- azCol = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0]));
- if( azCol==0 ){
- raw_printf(stderr, "Error: out of memory\n");
- exit(1);
- }
- }
- azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
- if( sqlite3_column_int(pStmt, 5) ){
- nPK++;
- if( nPK==1
- && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2),
- "INTEGER")==0
- ){
- isIPK = 1;
- }else{
- isIPK = 0;
- }
- }
- }
- sqlite3_finalize(pStmt);
- azCol[0] = 0;
- azCol[nCol+1] = 0;
-
- /* The decision of whether or not a rowid really needs to be preserved
- ** is tricky. We never need to preserve a rowid for a WITHOUT ROWID table
- ** or a table with an INTEGER PRIMARY KEY. We are unable to preserve
- ** rowids on tables where the rowid is inaccessible because there are other
- ** columns in the table named "rowid", "_rowid_", and "oid".
- */
- if( preserveRowid && isIPK ){
- /* If a single PRIMARY KEY column with type INTEGER was seen, then it
- ** might be an alise for the ROWID. But it might also be a WITHOUT ROWID
- ** table or a INTEGER PRIMARY KEY DESC column, neither of which are
- ** ROWID aliases. To distinguish these cases, check to see if
- ** there is a "pk" entry in "PRAGMA index_list". There will be
- ** no "pk" index if the PRIMARY KEY really is an alias for the ROWID.
- */
- zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)"
- " WHERE origin='pk'", zTab);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- sqlite3_free(zSql);
- if( rc ){
- freeColumnList(azCol);
- return 0;
- }
- rc = sqlite3_step(pStmt);
- sqlite3_finalize(pStmt);
- preserveRowid = rc==SQLITE_ROW;
- }
- if( preserveRowid ){
- /* Only preserve the rowid if we can find a name to use for the
- ** rowid */
- static char *azRowid[] = { "rowid", "_rowid_", "oid" };
- int i, j;
- for(j=0; j<3; j++){
- for(i=1; i<=nCol; i++){
- if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break;
- }
- if( i>nCol ){
- /* At this point, we know that azRowid[j] is not the name of any
- ** ordinary column in the table. Verify that azRowid[j] is a valid
- ** name for the rowid before adding it to azCol[0]. WITHOUT ROWID
- ** tables will fail this last check */
- rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
- if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
- break;
- }
- }
- }
- return azCol;
-}
-
-/*
-** Toggle the reverse_unordered_selects setting.
-*/
-static void toggleSelectOrder(sqlite3 *db){
- sqlite3_stmt *pStmt = 0;
- int iSetting = 0;
- char zStmt[100];
- sqlite3_prepare_v2(db, "PRAGMA reverse_unordered_selects", -1, &pStmt, 0);
- if( sqlite3_step(pStmt)==SQLITE_ROW ){
- iSetting = sqlite3_column_int(pStmt, 0);
- }
- sqlite3_finalize(pStmt);
- sqlite3_snprintf(sizeof(zStmt), zStmt,
- "PRAGMA reverse_unordered_selects(%d)", !iSetting);
- sqlite3_exec(db, zStmt, 0, 0, 0);
-}
-
-/*
-** This is a different callback routine used for dumping the database.
-** Each row received by this callback consists of a table name,
-** the table type ("index" or "table") and SQL to create the table.
-** This routine should print text sufficient to recreate the table.
-*/
-static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
- int rc;
- const char *zTable;
- const char *zType;
- const char *zSql;
- ShellState *p = (ShellState *)pArg;
-
- UNUSED_PARAMETER(azNotUsed);
- if( nArg!=3 ) return 1;
- zTable = azArg[0];
- zType = azArg[1];
- zSql = azArg[2];
-
- if( strcmp(zTable, "sqlite_sequence")==0 ){
- raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
- }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
- }else if( strncmp(zTable, "sqlite_", 7)==0 ){
- return 0;
- }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
- char *zIns;
- if( !p->writableSchema ){
- raw_printf(p->out, "PRAGMA writable_schema=ON;\n");
- p->writableSchema = 1;
- }
- zIns = sqlite3_mprintf(
- "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
- "VALUES('table','%q','%q',0,'%q');",
- zTable, zTable, zSql);
- utf8_printf(p->out, "%s\n", zIns);
- sqlite3_free(zIns);
- return 0;
- }else{
- printSchemaLine(p->out, zSql, ";\n");
- }
-
- if( strcmp(zType, "table")==0 ){
- ShellText sSelect;
- ShellText sTable;
- char **azCol;
- int i;
- char *savedDestTable;
- int savedMode;
-
- azCol = tableColumnList(p, zTable);
- if( azCol==0 ){
- p->nErr++;
- return 0;
- }
-
- /* Always quote the table name, even if it appears to be pure ascii,
- ** in case it is a keyword. Ex: INSERT INTO "table" ... */
- initText(&sTable);
- appendText(&sTable, zTable, quoteChar(zTable));
- /* If preserving the rowid, add a column list after the table name.
- ** In other words: "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
- ** instead of the usual "INSERT INTO tab VALUES(...)".
- */
- if( azCol[0] ){
- appendText(&sTable, "(", 0);
- appendText(&sTable, azCol[0], 0);
- for(i=1; azCol[i]; i++){
- appendText(&sTable, ",", 0);
- appendText(&sTable, azCol[i], quoteChar(azCol[i]));
- }
- appendText(&sTable, ")", 0);
- }
-
- /* Build an appropriate SELECT statement */
- initText(&sSelect);
- appendText(&sSelect, "SELECT ", 0);
- if( azCol[0] ){
- appendText(&sSelect, azCol[0], 0);
- appendText(&sSelect, ",", 0);
- }
- for(i=1; azCol[i]; i++){
- appendText(&sSelect, azCol[i], quoteChar(azCol[i]));
- if( azCol[i+1] ){
- appendText(&sSelect, ",", 0);
- }
- }
- freeColumnList(azCol);
- appendText(&sSelect, " FROM ", 0);
- appendText(&sSelect, zTable, quoteChar(zTable));
-
- savedDestTable = p->zDestTable;
- savedMode = p->mode;
- p->zDestTable = sTable.z;
- p->mode = p->cMode = MODE_Insert;
- rc = shell_exec(p->db, sSelect.z, shell_callback, p, 0);
- if( (rc&0xff)==SQLITE_CORRUPT ){
- raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
- toggleSelectOrder(p->db);
- shell_exec(p->db, sSelect.z, shell_callback, p, 0);
- toggleSelectOrder(p->db);
- }
- p->zDestTable = savedDestTable;
- p->mode = savedMode;
- freeText(&sTable);
- freeText(&sSelect);
- if( rc ) p->nErr++;
- }
- return 0;
-}
-
-/*
-** Run zQuery. Use dump_callback() as the callback routine so that
-** the contents of the query are output as SQL statements.
-**
-** If we get a SQLITE_CORRUPT error, rerun the query after appending
-** "ORDER BY rowid DESC" to the end.
-*/
-static int run_schema_dump_query(
- ShellState *p,
- const char *zQuery
-){
- int rc;
- char *zErr = 0;
- rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
- if( rc==SQLITE_CORRUPT ){
- char *zQ2;
- int len = strlen30(zQuery);
- raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
- if( zErr ){
- utf8_printf(p->out, "/****** %s ******/\n", zErr);
- sqlite3_free(zErr);
- zErr = 0;
- }
- zQ2 = malloc( len+100 );
- if( zQ2==0 ) return rc;
- sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
- rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
- if( rc ){
- utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr);
- }else{
- rc = SQLITE_CORRUPT;
- }
- sqlite3_free(zErr);
- free(zQ2);
- }
- return rc;
-}
-
-/*
-** Text of a help message
-*/
-static char zHelp[] =
-#ifndef SQLITE_OMIT_AUTHORIZATION
- ".auth ON|OFF Show authorizer callbacks\n"
-#endif
- ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
- ".bail on|off Stop after hitting an error. Default OFF\n"
- ".binary on|off Turn binary output on or off. Default OFF\n"
- ".cd DIRECTORY Change the working directory to DIRECTORY\n"
- ".changes on|off Show number of rows changed by SQL\n"
- ".check GLOB Fail if output since .testcase does not match\n"
- ".clone NEWDB Clone data into NEWDB from the existing database\n"
- ".databases List names and files of attached databases\n"
- ".dbinfo ?DB? Show status information about the database\n"
- ".dump ?TABLE? ... Dump the database in an SQL text format\n"
- " If TABLE specified, only dump tables matching\n"
- " LIKE pattern TABLE.\n"
- ".echo on|off Turn command echo on or off\n"
- ".eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN\n"
- ".exit Exit this program\n"
-/* Because explain mode comes on automatically now, the ".explain" mode
-** is removed from the help screen. It is still supported for legacy, however */
-/*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"*/
- ".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n"
- ".headers on|off Turn display of headers on or off\n"
- ".help Show this message\n"
- ".import FILE TABLE Import data from FILE into TABLE\n"
-#ifndef SQLITE_OMIT_TEST_CONTROL
- ".imposter INDEX TABLE Create imposter table TABLE on index INDEX\n"
-#endif
- ".indexes ?TABLE? Show names of all indexes\n"
- " If TABLE specified, only show indexes for tables\n"
- " matching LIKE pattern TABLE.\n"
-#ifdef SQLITE_ENABLE_IOTRACE
- ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
-#endif
- ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT\n"
- ".lint OPTIONS Report potential schema issues. Options:\n"
- " fkey-indexes Find missing foreign key indexes\n"
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
- ".load FILE ?ENTRY? Load an extension library\n"
-#endif
- ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n"
- ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
- " ascii Columns/rows delimited by 0x1F and 0x1E\n"
- " csv Comma-separated values\n"
- " column Left-aligned columns. (See .width)\n"
- " html HTML <table> code\n"
- " insert SQL insert statements for TABLE\n"
- " line One value per line\n"
- " list Values delimited by \"|\"\n"
- " quote Escape answers as for SQL\n"
- " tabs Tab-separated values\n"
- " tcl TCL list elements\n"
- ".nullvalue STRING Use STRING in place of NULL values\n"
- ".once FILENAME Output for the next SQL command only to FILENAME\n"
- ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n"
- " The --new option starts with an empty file\n"
- ".output ?FILENAME? Send output to FILENAME or stdout\n"
- ".print STRING... Print literal STRING\n"
- ".prompt MAIN CONTINUE Replace the standard prompts\n"
- ".quit Exit this program\n"
- ".read FILENAME Execute SQL in FILENAME\n"
- ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
- ".save FILE Write in-memory database into FILE\n"
- ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n"
- ".schema ?PATTERN? Show the CREATE statements matching PATTERN\n"
- " Add --indent for pretty-printing\n"
- ".selftest ?--init? Run tests defined in the SELFTEST table\n"
- ".separator COL ?ROW? Change the column separator and optionally the row\n"
- " separator for both the output mode and .import\n"
-#if defined(SQLITE_ENABLE_SESSION)
- ".session CMD ... Create or control sessions\n"
-#endif
- ".sha3sum ?OPTIONS...? Compute a SHA3 hash of database content\n"
- ".shell CMD ARGS... Run CMD ARGS... in a system shell\n"
- ".show Show the current values for various settings\n"
- ".stats ?on|off? Show stats or turn stats on or off\n"
- ".system CMD ARGS... Run CMD ARGS... in a system shell\n"
- ".tables ?TABLE? List names of tables\n"
- " If TABLE specified, only list tables matching\n"
- " LIKE pattern TABLE.\n"
- ".testcase NAME Begin redirecting output to 'testcase-out.txt'\n"
- ".timeout MS Try opening locked tables for MS milliseconds\n"
- ".timer on|off Turn SQL timer on or off\n"
- ".trace FILE|off Output each SQL statement as it is run\n"
- ".vfsinfo ?AUX? Information about the top-level VFS\n"
- ".vfslist List all available VFSes\n"
- ".vfsname ?AUX? Print the name of the VFS stack\n"
- ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
- " Negative values right-justify\n"
-;
-
-#if defined(SQLITE_ENABLE_SESSION)
-/*
-** Print help information for the ".sessions" command
-*/
-void session_help(ShellState *p){
- raw_printf(p->out,
- ".session ?NAME? SUBCOMMAND ?ARGS...?\n"
- "If ?NAME? is omitted, the first defined session is used.\n"
- "Subcommands:\n"
- " attach TABLE Attach TABLE\n"
- " changeset FILE Write a changeset into FILE\n"
- " close Close one session\n"
- " enable ?BOOLEAN? Set or query the enable bit\n"
- " filter GLOB... Reject tables matching GLOBs\n"
- " indirect ?BOOLEAN? Mark or query the indirect status\n"
- " isempty Query whether the session is empty\n"
- " list List currently open session names\n"
- " open DB NAME Open a new session on DB\n"
- " patchset FILE Write a patchset into FILE\n"
- );
-}
-#endif
-
-
-/* Forward reference */
-static int process_input(ShellState *p, FILE *in);
-
-/*
-** Read the content of file zName into memory obtained from sqlite3_malloc64()
-** and return a pointer to the buffer. The caller is responsible for freeing
-** the memory.
-**
-** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
-** read.
-**
-** For convenience, a nul-terminator byte is always appended to the data read
-** from the file before the buffer is returned. This byte is not included in
-** the final value of (*pnByte), if applicable.
-**
-** NULL is returned if any error is encountered. The final value of *pnByte
-** is undefined in this case.
-*/
-static char *readFile(const char *zName, int *pnByte){
- FILE *in = fopen(zName, "rb");
- long nIn;
- size_t nRead;
- char *pBuf;
- if( in==0 ) return 0;
- fseek(in, 0, SEEK_END);
- nIn = ftell(in);
- rewind(in);
- pBuf = sqlite3_malloc64( nIn+1 );
- if( pBuf==0 ) return 0;
- nRead = fread(pBuf, nIn, 1, in);
- fclose(in);
- if( nRead!=1 ){
- sqlite3_free(pBuf);
- return 0;
- }
- pBuf[nIn] = 0;
- if( pnByte ) *pnByte = nIn;
- return pBuf;
-}
-
-#if defined(SQLITE_ENABLE_SESSION)
-/*
-** Close a single OpenSession object and release all of its associated
-** resources.
-*/
-static void session_close(OpenSession *pSession){
- int i;
- sqlite3session_delete(pSession->p);
- sqlite3_free(pSession->zName);
- for(i=0; i<pSession->nFilter; i++){
- sqlite3_free(pSession->azFilter[i]);
- }
- sqlite3_free(pSession->azFilter);
- memset(pSession, 0, sizeof(OpenSession));
-}
-#endif
-
-/*
-** Close all OpenSession objects and release all associated resources.
-*/
-#if defined(SQLITE_ENABLE_SESSION)
-static void session_close_all(ShellState *p){
- int i;
- for(i=0; i<p->nSession; i++){
- session_close(&p->aSession[i]);
- }
- p->nSession = 0;
-}
-#else
-# define session_close_all(X)
-#endif
-
-/*
-** Implementation of the xFilter function for an open session. Omit
-** any tables named by ".session filter" but let all other table through.
-*/
-#if defined(SQLITE_ENABLE_SESSION)
-static int session_filter(void *pCtx, const char *zTab){
- OpenSession *pSession = (OpenSession*)pCtx;
- int i;
- for(i=0; i<pSession->nFilter; i++){
- if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0;
- }
- return 1;
-}
-#endif
-
-/*
-** Make sure the database is open. If it is not, then open it. If
-** the database fails to open, print an error message and exit.
-*/
-static void open_db(ShellState *p, int keepAlive){
- if( p->db==0 ){
- sqlite3_initialize();
- sqlite3_open(p->zDbFilename, &p->db);
- globalDb = p->db;
- if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
- utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
- p->zDbFilename, sqlite3_errmsg(p->db));
- if( keepAlive ) return;
- exit(1);
- }
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
- sqlite3_enable_load_extension(p->db, 1);
-#endif
- sqlite3_fileio_init(p->db, 0, 0);
- sqlite3_shathree_init(p->db, 0, 0);
- sqlite3_completion_init(p->db, 0, 0);
- sqlite3_create_function(p->db, "shell_add_schema", 2, SQLITE_UTF8, 0,
- shellAddSchemaName, 0, 0);
- }
-}
-
-#if HAVE_READLINE || HAVE_EDITLINE
-/*
-** Readline completion callbacks
-*/
-static char *readline_completion_generator(const char *text, int state){
- static sqlite3_stmt *pStmt = 0;
- char *zRet;
- if( state==0 ){
- char *zSql;
- sqlite3_finalize(pStmt);
- zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
- " FROM completion(%Q) ORDER BY 1", text);
- sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
- sqlite3_free(zSql);
- }
- if( sqlite3_step(pStmt)==SQLITE_ROW ){
- zRet = strdup((const char*)sqlite3_column_text(pStmt, 0));
- }else{
- sqlite3_finalize(pStmt);
- pStmt = 0;
- zRet = 0;
- }
- return zRet;
-}
-static char **readline_completion(const char *zText, int iStart, int iEnd){
- rl_attempted_completion_over = 1;
- return rl_completion_matches(zText, readline_completion_generator);
-}
-
-#elif HAVE_LINENOISE
-/*
-** Linenoise completion callback
-*/
-static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
- int nLine = (int)strlen(zLine);
- int i, iStart;
- sqlite3_stmt *pStmt = 0;
- char *zSql;
- char zBuf[1000];
-
- if( nLine>sizeof(zBuf)-30 ) return;
- if( zLine[0]=='.' ) return;
- for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
- if( i==nLine-1 ) return;
- iStart = i+1;
- memcpy(zBuf, zLine, iStart);
- zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
- " FROM completion(%Q,%Q) ORDER BY 1",
- &zLine[iStart], zLine);
- sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
- sqlite3_free(zSql);
- sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */
- while( sqlite3_step(pStmt)==SQLITE_ROW ){
- const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0);
- int nCompletion = sqlite3_column_bytes(pStmt, 0);
- if( iStart+nCompletion < sizeof(zBuf)-1 ){
- memcpy(zBuf+iStart, zCompletion, nCompletion+1);
- linenoiseAddCompletion(lc, zBuf);
- }
- }
- sqlite3_finalize(pStmt);
-}
-#endif
-
-/*
-** Do C-language style dequoting.
-**
-** \a -> alarm
-** \b -> backspace
-** \t -> tab
-** \n -> newline
-** \v -> vertical tab
-** \f -> form feed
-** \r -> carriage return
-** \s -> space
-** \" -> "
-** \' -> '
-** \\ -> backslash
-** \NNN -> ascii character NNN in octal
-*/
-static void resolve_backslashes(char *z){
- int i, j;
- char c;
- while( *z && *z!='\\' ) z++;
- for(i=j=0; (c = z[i])!=0; i++, j++){
- if( c=='\\' && z[i+1]!=0 ){
- c = z[++i];
- if( c=='a' ){
- c = '\a';
- }else if( c=='b' ){
- c = '\b';
- }else if( c=='t' ){
- c = '\t';
- }else if( c=='n' ){
- c = '\n';
- }else if( c=='v' ){
- c = '\v';
- }else if( c=='f' ){
- c = '\f';
- }else if( c=='r' ){
- c = '\r';
- }else if( c=='"' ){
- c = '"';
- }else if( c=='\'' ){
- c = '\'';
- }else if( c=='\\' ){
- c = '\\';
- }else if( c>='0' && c<='7' ){
- c -= '0';
- if( z[i+1]>='0' && z[i+1]<='7' ){
- i++;
- c = (c<<3) + z[i] - '0';
- if( z[i+1]>='0' && z[i+1]<='7' ){
- i++;
- c = (c<<3) + z[i] - '0';
- }
- }
- }
- }
- z[j] = c;
- }
- if( j<i ) z[j] = 0;
-}
-
-/*
-** Return the value of a hexadecimal digit. Return -1 if the input
-** is not a hex digit.
-*/
-static int hexDigitValue(char c){
- if( c>='0' && c<='9' ) return c - '0';
- if( c>='a' && c<='f' ) return c - 'a' + 10;
- if( c>='A' && c<='F' ) return c - 'A' + 10;
- return -1;
-}
-
-/*
-** Interpret zArg as an integer value, possibly with suffixes.
-*/
-static sqlite3_int64 integerValue(const char *zArg){
- sqlite3_int64 v = 0;
- static const struct { char *zSuffix; int iMult; } aMult[] = {
- { "KiB", 1024 },
- { "MiB", 1024*1024 },
- { "GiB", 1024*1024*1024 },
- { "KB", 1000 },
- { "MB", 1000000 },
- { "GB", 1000000000 },
- { "K", 1000 },
- { "M", 1000000 },
- { "G", 1000000000 },
- };
- int i;
- int isNeg = 0;
- if( zArg[0]=='-' ){
- isNeg = 1;
- zArg++;
- }else if( zArg[0]=='+' ){
- zArg++;
- }
- if( zArg[0]=='0' && zArg[1]=='x' ){
- int x;
- zArg += 2;
- while( (x = hexDigitValue(zArg[0]))>=0 ){
- v = (v<<4) + x;
- zArg++;
- }
- }else{
- while( IsDigit(zArg[0]) ){
- v = v*10 + zArg[0] - '0';
- zArg++;
- }
- }
- for(i=0; i<ArraySize(aMult); i++){
- if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
- v *= aMult[i].iMult;
- break;
- }
- }
- return isNeg? -v : v;
-}
-
-/*
-** Interpret zArg as either an integer or a boolean value. Return 1 or 0
-** for TRUE and FALSE. Return the integer value if appropriate.
-*/
-static int booleanValue(const char *zArg){
- int i;
- if( zArg[0]=='0' && zArg[1]=='x' ){
- for(i=2; hexDigitValue(zArg[i])>=0; i++){}
- }else{
- for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
- }
- if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
- if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
- return 1;
- }
- if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
- return 0;
- }
- utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
- zArg);
- return 0;
-}
-
-/*
-** Set or clear a shell flag according to a boolean value.
-*/
-static void setOrClearFlag(ShellState *p, unsigned mFlag, const char *zArg){
- if( booleanValue(zArg) ){
- ShellSetFlag(p, mFlag);
- }else{
- ShellClearFlag(p, mFlag);
- }
-}
-
-/*
-** Close an output file, assuming it is not stderr or stdout
-*/
-static void output_file_close(FILE *f){
- if( f && f!=stdout && f!=stderr ) fclose(f);
-}
-
-/*
-** Try to open an output file. The names "stdout" and "stderr" are
-** recognized and do the right thing. NULL is returned if the output
-** filename is "off".
-*/
-static FILE *output_file_open(const char *zFile){
- FILE *f;
- if( strcmp(zFile,"stdout")==0 ){
- f = stdout;
- }else if( strcmp(zFile, "stderr")==0 ){
- f = stderr;
- }else if( strcmp(zFile, "off")==0 ){
- f = 0;
- }else{
- f = fopen(zFile, "wb");
- if( f==0 ){
- utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
- }
- }
- return f;
-}
-
-#if !defined(SQLITE_UNTESTABLE)
-#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
-/*
-** A routine for handling output from sqlite3_trace().
-*/
-static int sql_trace_callback(
- unsigned mType,
- void *pArg,
- void *pP,
- void *pX
-){
- FILE *f = (FILE*)pArg;
- UNUSED_PARAMETER(mType);
- UNUSED_PARAMETER(pP);
- if( f ){
- const char *z = (const char*)pX;
- int i = (int)strlen(z);
- while( i>0 && z[i-1]==';' ){ i--; }
- utf8_printf(f, "%.*s;\n", i, z);
- }
- return 0;
-}
-#endif
-#endif
-
-/*
-** A no-op routine that runs with the ".breakpoint" doc-command. This is
-** a useful spot to set a debugger breakpoint.
-*/
-static void test_breakpoint(void){
- static int nCall = 0;
- nCall++;
-}
-
-/*
-** An object used to read a CSV and other files for import.
-*/
-typedef struct ImportCtx ImportCtx;
-struct ImportCtx {
- const char *zFile; /* Name of the input file */
- FILE *in; /* Read the CSV text from this input stream */
- char *z; /* Accumulated text for a field */
- int n; /* Number of bytes in z */
- int nAlloc; /* Space allocated for z[] */
- int nLine; /* Current line number */
- int bNotFirst; /* True if one or more bytes already read */
- int cTerm; /* Character that terminated the most recent field */
- int cColSep; /* The column separator character. (Usually ",") */
- int cRowSep; /* The row separator character. (Usually "\n") */
-};
-
-/* Append a single byte to z[] */
-static void import_append_char(ImportCtx *p, int c){
- if( p->n+1>=p->nAlloc ){
- p->nAlloc += p->nAlloc + 100;
- p->z = sqlite3_realloc64(p->z, p->nAlloc);
- if( p->z==0 ){
- raw_printf(stderr, "out of memory\n");
- exit(1);
- }
- }
- p->z[p->n++] = (char)c;
-}
-
-/* Read a single field of CSV text. Compatible with rfc4180 and extended
-** with the option of having a separator other than ",".
-**
-** + Input comes from p->in.
-** + Store results in p->z of length p->n. Space to hold p->z comes
-** from sqlite3_malloc64().
-** + Use p->cSep as the column separator. The default is ",".
-** + Use p->rSep as the row separator. The default is "\n".
-** + Keep track of the line number in p->nLine.
-** + Store the character that terminates the field in p->cTerm. Store
-** EOF on end-of-file.
-** + Report syntax errors on stderr
-*/
-static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
- int c;
- int cSep = p->cColSep;
- int rSep = p->cRowSep;
- p->n = 0;
- c = fgetc(p->in);
- if( c==EOF || seenInterrupt ){
- p->cTerm = EOF;
- return 0;
- }
- if( c=='"' ){
- int pc, ppc;
- int startLine = p->nLine;
- int cQuote = c;
- pc = ppc = 0;
- while( 1 ){
- c = fgetc(p->in);
- if( c==rSep ) p->nLine++;
- if( c==cQuote ){
- if( pc==cQuote ){
- pc = 0;
- continue;
- }
- }
- if( (c==cSep && pc==cQuote)
- || (c==rSep && pc==cQuote)
- || (c==rSep && pc=='\r' && ppc==cQuote)
- || (c==EOF && pc==cQuote)
- ){
- do{ p->n--; }while( p->z[p->n]!=cQuote );
- p->cTerm = c;
- break;
- }
- if( pc==cQuote && c!='\r' ){
- utf8_printf(stderr, "%s:%d: unescaped %c character\n",
- p->zFile, p->nLine, cQuote);
- }
- if( c==EOF ){
- utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n",
- p->zFile, startLine, cQuote);
- p->cTerm = c;
- break;
- }
- import_append_char(p, c);
- ppc = pc;
- pc = c;
- }
- }else{
- /* If this is the first field being parsed and it begins with the
- ** UTF-8 BOM (0xEF BB BF) then skip the BOM */
- if( (c&0xff)==0xef && p->bNotFirst==0 ){
- import_append_char(p, c);
- c = fgetc(p->in);
- if( (c&0xff)==0xbb ){
- import_append_char(p, c);
- c = fgetc(p->in);
- if( (c&0xff)==0xbf ){
- p->bNotFirst = 1;
- p->n = 0;
- return csv_read_one_field(p);
- }
- }
- }
- while( c!=EOF && c!=cSep && c!=rSep ){
- import_append_char(p, c);
- c = fgetc(p->in);
- }
- if( c==rSep ){
- p->nLine++;
- if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
- }
- p->cTerm = c;
- }
- if( p->z ) p->z[p->n] = 0;
- p->bNotFirst = 1;
- return p->z;
-}
-
-/* Read a single field of ASCII delimited text.
-**
-** + Input comes from p->in.
-** + Store results in p->z of length p->n. Space to hold p->z comes
-** from sqlite3_malloc64().
-** + Use p->cSep as the column separator. The default is "\x1F".
-** + Use p->rSep as the row separator. The default is "\x1E".
-** + Keep track of the row number in p->nLine.
-** + Store the character that terminates the field in p->cTerm. Store
-** EOF on end-of-file.
-** + Report syntax errors on stderr
-*/
-static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
- int c;
- int cSep = p->cColSep;
- int rSep = p->cRowSep;
- p->n = 0;
- c = fgetc(p->in);
- if( c==EOF || seenInterrupt ){
- p->cTerm = EOF;
- return 0;
- }
- while( c!=EOF && c!=cSep && c!=rSep ){
- import_append_char(p, c);
- c = fgetc(p->in);
- }
- if( c==rSep ){
- p->nLine++;
- }
- p->cTerm = c;
- if( p->z ) p->z[p->n] = 0;
- return p->z;
-}
-
-/*
-** Try to transfer data for table zTable. If an error is seen while
-** moving forward, try to go backwards. The backwards movement won't
-** work for WITHOUT ROWID tables.
-*/
-static void tryToCloneData(
- ShellState *p,
- sqlite3 *newDb,
- const char *zTable
-){
- sqlite3_stmt *pQuery = 0;
- sqlite3_stmt *pInsert = 0;
- char *zQuery = 0;
- char *zInsert = 0;
- int rc;
- int i, j, n;
- int nTable = (int)strlen(zTable);
- int k = 0;
- int cnt = 0;
- const int spinRate = 10000;
-
- zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
- rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
- if( rc ){
- utf8_printf(stderr, "Error %d: %s on [%s]\n",
- sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
- zQuery);
- goto end_data_xfer;
- }
- n = sqlite3_column_count(pQuery);
- zInsert = sqlite3_malloc64(200 + nTable + n*3);
- if( zInsert==0 ){
- raw_printf(stderr, "out of memory\n");
- goto end_data_xfer;
- }
- sqlite3_snprintf(200+nTable,zInsert,
- "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
- i = (int)strlen(zInsert);
- for(j=1; j<n; j++){
- memcpy(zInsert+i, ",?", 2);
- i += 2;
- }
- memcpy(zInsert+i, ");", 3);
- rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
- if( rc ){
- utf8_printf(stderr, "Error %d: %s on [%s]\n",
- sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
- zQuery);
- goto end_data_xfer;
- }
- for(k=0; k<2; k++){
- while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
- for(i=0; i<n; i++){
- switch( sqlite3_column_type(pQuery, i) ){
- case SQLITE_NULL: {
- sqlite3_bind_null(pInsert, i+1);
- break;
- }
- case SQLITE_INTEGER: {
- sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
- break;
- }
- case SQLITE_FLOAT: {
- sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
- break;
- }
- case SQLITE_TEXT: {
- sqlite3_bind_text(pInsert, i+1,
- (const char*)sqlite3_column_text(pQuery,i),
- -1, SQLITE_STATIC);
- break;
- }
- case SQLITE_BLOB: {
- sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
- sqlite3_column_bytes(pQuery,i),
- SQLITE_STATIC);
- break;
- }
- }
- } /* End for */
- rc = sqlite3_step(pInsert);
- if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
- utf8_printf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
- sqlite3_errmsg(newDb));
- }
- sqlite3_reset(pInsert);
- cnt++;
- if( (cnt%spinRate)==0 ){
- printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
- fflush(stdout);
- }
- } /* End while */
- if( rc==SQLITE_DONE ) break;
- sqlite3_finalize(pQuery);
- sqlite3_free(zQuery);
- zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
- zTable);
- rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
- if( rc ){
- utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
- break;
- }
- } /* End for(k=0...) */
-
-end_data_xfer:
- sqlite3_finalize(pQuery);
- sqlite3_finalize(pInsert);
- sqlite3_free(zQuery);
- sqlite3_free(zInsert);
-}
-
-
-/*
-** Try to transfer all rows of the schema that match zWhere. For
-** each row, invoke xForEach() on the object defined by that row.
-** If an error is encountered while moving forward through the
-** sqlite_master table, try again moving backwards.
-*/
-static void tryToCloneSchema(
- ShellState *p,
- sqlite3 *newDb,
- const char *zWhere,
- void (*xForEach)(ShellState*,sqlite3*,const char*)
-){
- sqlite3_stmt *pQuery = 0;
- char *zQuery = 0;
- int rc;
- const unsigned char *zName;
- const unsigned char *zSql;
- char *zErrMsg = 0;
-
- zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
- " WHERE %s", zWhere);
- rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
- if( rc ){
- utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
- sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
- zQuery);
- goto end_schema_xfer;
- }
- while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
- zName = sqlite3_column_text(pQuery, 0);
- zSql = sqlite3_column_text(pQuery, 1);
- printf("%s... ", zName); fflush(stdout);
- sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
- if( zErrMsg ){
- utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
- sqlite3_free(zErrMsg);
- zErrMsg = 0;
- }
- if( xForEach ){
- xForEach(p, newDb, (const char*)zName);
- }
- printf("done\n");
- }
- if( rc!=SQLITE_DONE ){
- sqlite3_finalize(pQuery);
- sqlite3_free(zQuery);
- zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
- " WHERE %s ORDER BY rowid DESC", zWhere);
- rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
- if( rc ){
- utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
- sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
- zQuery);
- goto end_schema_xfer;
- }
- while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
- zName = sqlite3_column_text(pQuery, 0);
- zSql = sqlite3_column_text(pQuery, 1);
- printf("%s... ", zName); fflush(stdout);
- sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
- if( zErrMsg ){
- utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
- sqlite3_free(zErrMsg);
- zErrMsg = 0;
- }
- if( xForEach ){
- xForEach(p, newDb, (const char*)zName);
- }
- printf("done\n");
- }
- }
-end_schema_xfer:
- sqlite3_finalize(pQuery);
- sqlite3_free(zQuery);
-}
-
-/*
-** Open a new database file named "zNewDb". Try to recover as much information
-** as possible out of the main database (which might be corrupt) and write it
-** into zNewDb.
-*/
-static void tryToClone(ShellState *p, const char *zNewDb){
- int rc;
- sqlite3 *newDb = 0;
- if( access(zNewDb,0)==0 ){
- utf8_printf(stderr, "File \"%s\" already exists.\n", zNewDb);
- return;
- }
- rc = sqlite3_open(zNewDb, &newDb);
- if( rc ){
- utf8_printf(stderr, "Cannot create output database: %s\n",
- sqlite3_errmsg(newDb));
- }else{
- sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
- sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
- tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
- tryToCloneSchema(p, newDb, "type!='table'", 0);
- sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
- sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
- }
- sqlite3_close(newDb);
-}
-
-/*
-** Change the output file back to stdout
-*/
-static void output_reset(ShellState *p){
- if( p->outfile[0]=='|' ){
-#ifndef SQLITE_OMIT_POPEN
- pclose(p->out);
-#endif
- }else{
- output_file_close(p->out);
- }
- p->outfile[0] = 0;
- p->out = stdout;
-}
-
-/*
-** Run an SQL command and return the single integer result.
-*/
-static int db_int(ShellState *p, const char *zSql){
- sqlite3_stmt *pStmt;
- int res = 0;
- sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
- res = sqlite3_column_int(pStmt,0);
- }
- sqlite3_finalize(pStmt);
- return res;
-}
-
-/*
-** Convert a 2-byte or 4-byte big-endian integer into a native integer
-*/
-static unsigned int get2byteInt(unsigned char *a){
- return (a[0]<<8) + a[1];
-}
-static unsigned int get4byteInt(unsigned char *a){
- return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
-}
-
-/*
-** Implementation of the ".info" command.
-**
-** Return 1 on error, 2 to exit, and 0 otherwise.
-*/
-static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
- static const struct { const char *zName; int ofst; } aField[] = {
- { "file change counter:", 24 },
- { "database page count:", 28 },
- { "freelist page count:", 36 },
- { "schema cookie:", 40 },
- { "schema format:", 44 },
- { "default cache size:", 48 },
- { "autovacuum top root:", 52 },
- { "incremental vacuum:", 64 },
- { "text encoding:", 56 },
- { "user version:", 60 },
- { "application id:", 68 },
- { "software version:", 96 },
- };
- static const struct { const char *zName; const char *zSql; } aQuery[] = {
- { "number of tables:",
- "SELECT count(*) FROM %s WHERE type='table'" },
- { "number of indexes:",
- "SELECT count(*) FROM %s WHERE type='index'" },
- { "number of triggers:",
- "SELECT count(*) FROM %s WHERE type='trigger'" },
- { "number of views:",
- "SELECT count(*) FROM %s WHERE type='view'" },
- { "schema size:",
- "SELECT total(length(sql)) FROM %s" },
- };
- sqlite3_file *pFile = 0;
- int i;
- char *zSchemaTab;
- char *zDb = nArg>=2 ? azArg[1] : "main";
- unsigned char aHdr[100];
- open_db(p, 0);
- if( p->db==0 ) return 1;
- sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
- if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
- return 1;
- }
- i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
- if( i!=SQLITE_OK ){
- raw_printf(stderr, "unable to read database header\n");
- return 1;
- }
- i = get2byteInt(aHdr+16);
- if( i==1 ) i = 65536;
- utf8_printf(p->out, "%-20s %d\n", "database page size:", i);
- utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]);
- utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]);
- utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]);
- for(i=0; i<ArraySize(aField); i++){
- int ofst = aField[i].ofst;
- unsigned int val = get4byteInt(aHdr + ofst);
- utf8_printf(p->out, "%-20s %u", aField[i].zName, val);
- switch( ofst ){
- case 56: {
- if( val==1 ) raw_printf(p->out, " (utf8)");
- if( val==2 ) raw_printf(p->out, " (utf16le)");
- if( val==3 ) raw_printf(p->out, " (utf16be)");
- }
- }
- raw_printf(p->out, "\n");
- }
- if( zDb==0 ){
- zSchemaTab = sqlite3_mprintf("main.sqlite_master");
- }else if( strcmp(zDb,"temp")==0 ){
- zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
- }else{
- zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
- }
- for(i=0; i<ArraySize(aQuery); i++){
- char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
- int val = db_int(p, zSql);
- sqlite3_free(zSql);
- utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
- }
- sqlite3_free(zSchemaTab);
- return 0;
-}
-
-/*
-** Print the current sqlite3_errmsg() value to stderr and return 1.
-*/
-static int shellDatabaseError(sqlite3 *db){
- const char *zErr = sqlite3_errmsg(db);
- utf8_printf(stderr, "Error: %s\n", zErr);
- return 1;
-}
-
-/*
-** Print an out-of-memory message to stderr and return 1.
-*/
-static int shellNomemError(void){
- raw_printf(stderr, "Error: out of memory\n");
- return 1;
-}
-
-/*
-** Compare the pattern in zGlob[] against the text in z[]. Return TRUE
-** if they match and FALSE (0) if they do not match.
-**
-** Globbing rules:
-**
-** '*' Matches any sequence of zero or more characters.
-**
-** '?' Matches exactly one character.
-**
-** [...] Matches one character from the enclosed list of
-** characters.
-**
-** [^...] Matches one character not in the enclosed list.
-**
-** '#' Matches any sequence of one or more digits with an
-** optional + or - sign in front
-**
-** ' ' Any span of whitespace matches any other span of
-** whitespace.
-**
-** Extra whitespace at the end of z[] is ignored.
-*/
-static int testcase_glob(const char *zGlob, const char *z){
- int c, c2;
- int invert;
- int seen;
-
- while( (c = (*(zGlob++)))!=0 ){
- if( IsSpace(c) ){
- if( !IsSpace(*z) ) return 0;
- while( IsSpace(*zGlob) ) zGlob++;
- while( IsSpace(*z) ) z++;
- }else if( c=='*' ){
- while( (c=(*(zGlob++))) == '*' || c=='?' ){
- if( c=='?' && (*(z++))==0 ) return 0;
- }
- if( c==0 ){
- return 1;
- }else if( c=='[' ){
- while( *z && testcase_glob(zGlob-1,z)==0 ){
- z++;
- }
- return (*z)!=0;
- }
- while( (c2 = (*(z++)))!=0 ){
- while( c2!=c ){
- c2 = *(z++);
- if( c2==0 ) return 0;
- }
- if( testcase_glob(zGlob,z) ) return 1;
- }
- return 0;
- }else if( c=='?' ){
- if( (*(z++))==0 ) return 0;
- }else if( c=='[' ){
- int prior_c = 0;
- seen = 0;
- invert = 0;
- c = *(z++);
- if( c==0 ) return 0;
- c2 = *(zGlob++);
- if( c2=='^' ){
- invert = 1;
- c2 = *(zGlob++);
- }
- if( c2==']' ){
- if( c==']' ) seen = 1;
- c2 = *(zGlob++);
- }
- while( c2 && c2!=']' ){
- if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
- c2 = *(zGlob++);
- if( c>=prior_c && c<=c2 ) seen = 1;
- prior_c = 0;
- }else{
- if( c==c2 ){
- seen = 1;
- }
- prior_c = c2;
- }
- c2 = *(zGlob++);
- }
- if( c2==0 || (seen ^ invert)==0 ) return 0;
- }else if( c=='#' ){
- if( (z[0]=='-' || z[0]=='+') && IsDigit(z[1]) ) z++;
- if( !IsDigit(z[0]) ) return 0;
- z++;
- while( IsDigit(z[0]) ){ z++; }
- }else{
- if( c!=(*(z++)) ) return 0;
- }
- }
- while( IsSpace(*z) ){ z++; }
- return *z==0;
-}
-
-
-/*
-** Compare the string as a command-line option with either one or two
-** initial "-" characters.
-*/
-static int optionMatch(const char *zStr, const char *zOpt){
- if( zStr[0]!='-' ) return 0;
- zStr++;
- if( zStr[0]=='-' ) zStr++;
- return strcmp(zStr, zOpt)==0;
-}
-
-/*
-** Delete a file.
-*/
-int shellDeleteFile(const char *zFilename){
- int rc;
-#ifdef _WIN32
- wchar_t *z = sqlite3_win32_utf8_to_unicode(zFilename);
- rc = _wunlink(z);
- sqlite3_free(z);
-#else
- rc = unlink(zFilename);
-#endif
- return rc;
-}
-
-
-/*
-** The implementation of SQL scalar function fkey_collate_clause(), used
-** by the ".lint fkey-indexes" command. This scalar function is always
-** called with four arguments - the parent table name, the parent column name,
-** the child table name and the child column name.
-**
-** fkey_collate_clause('parent-tab', 'parent-col', 'child-tab', 'child-col')
-**
-** If either of the named tables or columns do not exist, this function
-** returns an empty string. An empty string is also returned if both tables
-** and columns exist but have the same default collation sequence. Or,
-** if both exist but the default collation sequences are different, this
-** function returns the string " COLLATE <parent-collation>", where
-** <parent-collation> is the default collation sequence of the parent column.
-*/
-static void shellFkeyCollateClause(
- sqlite3_context *pCtx,
- int nVal,
- sqlite3_value **apVal
-){
- sqlite3 *db = sqlite3_context_db_handle(pCtx);
- const char *zParent;
- const char *zParentCol;
- const char *zParentSeq;
- const char *zChild;
- const char *zChildCol;
- const char *zChildSeq = 0; /* Initialize to avoid false-positive warning */
- int rc;
-
- assert( nVal==4 );
- zParent = (const char*)sqlite3_value_text(apVal[0]);
- zParentCol = (const char*)sqlite3_value_text(apVal[1]);
- zChild = (const char*)sqlite3_value_text(apVal[2]);
- zChildCol = (const char*)sqlite3_value_text(apVal[3]);
-
- sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
- rc = sqlite3_table_column_metadata(
- db, "main", zParent, zParentCol, 0, &zParentSeq, 0, 0, 0
- );
- if( rc==SQLITE_OK ){
- rc = sqlite3_table_column_metadata(
- db, "main", zChild, zChildCol, 0, &zChildSeq, 0, 0, 0
- );
- }
-
- if( rc==SQLITE_OK && sqlite3_stricmp(zParentSeq, zChildSeq) ){
- char *z = sqlite3_mprintf(" COLLATE %s", zParentSeq);
- sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
- sqlite3_free(z);
- }
-}
-
-
-/*
-** The implementation of dot-command ".lint fkey-indexes".
-*/
-static int lintFkeyIndexes(
- ShellState *pState, /* Current shell tool state */
- char **azArg, /* Array of arguments passed to dot command */
- int nArg /* Number of entries in azArg[] */
-){
- sqlite3 *db = pState->db; /* Database handle to query "main" db of */
- FILE *out = pState->out; /* Stream to write non-error output to */
- int bVerbose = 0; /* If -verbose is present */
- int bGroupByParent = 0; /* If -groupbyparent is present */
- int i; /* To iterate through azArg[] */
- const char *zIndent = ""; /* How much to indent CREATE INDEX by */
- int rc; /* Return code */
- sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
-
- /*
- ** This SELECT statement returns one row for each foreign key constraint
- ** in the schema of the main database. The column values are:
- **
- ** 0. The text of an SQL statement similar to:
- **
- ** "EXPLAIN QUERY PLAN SELECT rowid FROM child_table WHERE child_key=?"
- **
- ** This is the same SELECT that the foreign keys implementation needs
- ** to run internally on child tables. If there is an index that can
- ** be used to optimize this query, then it can also be used by the FK
- ** implementation to optimize DELETE or UPDATE statements on the parent
- ** table.
- **
- ** 1. A GLOB pattern suitable for sqlite3_strglob(). If the plan output by
- ** the EXPLAIN QUERY PLAN command matches this pattern, then the schema
- ** contains an index that can be used to optimize the query.
- **
- ** 2. Human readable text that describes the child table and columns. e.g.
- **
- ** "child_table(child_key1, child_key2)"
- **
- ** 3. Human readable text that describes the parent table and columns. e.g.
- **
- ** "parent_table(parent_key1, parent_key2)"
- **
- ** 4. A full CREATE INDEX statement for an index that could be used to
- ** optimize DELETE or UPDATE statements on the parent table. e.g.
- **
- ** "CREATE INDEX child_table_child_key ON child_table(child_key)"
- **
- ** 5. The name of the parent table.
- **
- ** These six values are used by the C logic below to generate the report.
- */
- const char *zSql =
- "SELECT "
- " 'EXPLAIN QUERY PLAN SELECT rowid FROM ' || quote(s.name) || ' WHERE '"
- " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
- " || fkey_collate_clause("
- " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
- ", "
- " 'SEARCH TABLE ' || s.name || ' USING COVERING INDEX*('"
- " || group_concat('*=?', ' AND ') || ')'"
- ", "
- " s.name || '(' || group_concat(f.[from], ', ') || ')'"
- ", "
- " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
- ", "
- " 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
- " || ' ON ' || quote(s.name) || '('"
- " || group_concat(quote(f.[from]) ||"
- " fkey_collate_clause("
- " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
- " || ');'"
- ", "
- " f.[table] "
- "FROM sqlite_master AS s, pragma_foreign_key_list(s.name) AS f "
- "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
- "GROUP BY s.name, f.id "
- "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
- ;
- const char *zGlobIPK = "SEARCH TABLE * USING INTEGER PRIMARY KEY (rowid=?)";
-
- for(i=2; i<nArg; i++){
- int n = (int)strlen(azArg[i]);
- if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
- bVerbose = 1;
- }
- else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
- bGroupByParent = 1;
- zIndent = " ";
- }
- else{
- raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n",
- azArg[0], azArg[1]
- );
- return SQLITE_ERROR;
- }
- }
-
- /* Register the fkey_collate_clause() SQL function */
- rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
- 0, shellFkeyCollateClause, 0, 0
- );
-
-
- if( rc==SQLITE_OK ){
- rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
- }
- if( rc==SQLITE_OK ){
- sqlite3_bind_int(pSql, 1, bGroupByParent);
- }
-
- if( rc==SQLITE_OK ){
- int rc2;
- char *zPrev = 0;
- while( SQLITE_ROW==sqlite3_step(pSql) ){
- int res = -1;
- sqlite3_stmt *pExplain = 0;
- const char *zEQP = (const char*)sqlite3_column_text(pSql, 0);
- const char *zGlob = (const char*)sqlite3_column_text(pSql, 1);
- const char *zFrom = (const char*)sqlite3_column_text(pSql, 2);
- const char *zTarget = (const char*)sqlite3_column_text(pSql, 3);
- const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
- const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
-
- rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
- if( rc!=SQLITE_OK ) break;
- if( SQLITE_ROW==sqlite3_step(pExplain) ){
- const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
- res = (
- 0==sqlite3_strglob(zGlob, zPlan)
- || 0==sqlite3_strglob(zGlobIPK, zPlan)
- );
- }
- rc = sqlite3_finalize(pExplain);
- if( rc!=SQLITE_OK ) break;
-
- if( res<0 ){
- raw_printf(stderr, "Error: internal error");
- break;
- }else{
- if( bGroupByParent
- && (bVerbose || res==0)
- && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
- ){
- raw_printf(out, "-- Parent table %s\n", zParent);
- sqlite3_free(zPrev);
- zPrev = sqlite3_mprintf("%s", zParent);
- }
-
- if( res==0 ){
- raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
- }else if( bVerbose ){
- raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
- zIndent, zFrom, zTarget
- );
- }
- }
- }
- sqlite3_free(zPrev);
-
- if( rc!=SQLITE_OK ){
- raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
- }
-
- rc2 = sqlite3_finalize(pSql);
- if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
- rc = rc2;
- raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
- }
- }else{
- raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
- }
-
- return rc;
-}
-
-/*
-** Implementation of ".lint" dot command.
-*/
-static int lintDotCommand(
- ShellState *pState, /* Current shell tool state */
- char **azArg, /* Array of arguments passed to dot command */
- int nArg /* Number of entries in azArg[] */
-){
- int n;
- n = (nArg>=2 ? (int)strlen(azArg[1]) : 0);
- if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
- return lintFkeyIndexes(pState, azArg, nArg);
-
- usage:
- raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
- raw_printf(stderr, "Where sub-commands are:\n");
- raw_printf(stderr, " fkey-indexes\n");
- return SQLITE_ERROR;
-}
-
-
-/*
-** If an input line begins with "." then invoke this routine to
-** process that line.
-**
-** Return 1 on error, 2 to exit, and 0 otherwise.
-*/
-static int do_meta_command(char *zLine, ShellState *p){
- int h = 1;
- int nArg = 0;
- int n, c;
- int rc = 0;
- char *azArg[50];
-
- /* Parse the input line into tokens.
- */
- while( zLine[h] && nArg<ArraySize(azArg) ){
- while( IsSpace(zLine[h]) ){ h++; }
- if( zLine[h]==0 ) break;
- if( zLine[h]=='\'' || zLine[h]=='"' ){
- int delim = zLine[h++];
- azArg[nArg++] = &zLine[h];
- while( zLine[h] && zLine[h]!=delim ){
- if( zLine[h]=='\\' && delim=='"' && zLine[h+1]!=0 ) h++;
- h++;
- }
- if( zLine[h]==delim ){
- zLine[h++] = 0;
- }
- if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
- }else{
- azArg[nArg++] = &zLine[h];
- while( zLine[h] && !IsSpace(zLine[h]) ){ h++; }
- if( zLine[h] ) zLine[h++] = 0;
- resolve_backslashes(azArg[nArg-1]);
- }
- }
-
- /* Process the input line.
- */
- if( nArg==0 ) return 0; /* no tokens, no error */
- n = strlen30(azArg[0]);
- c = azArg[0][0];
-
-#ifndef SQLITE_OMIT_AUTHORIZATION
- if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){
- if( nArg!=2 ){
- raw_printf(stderr, "Usage: .auth ON|OFF\n");
- rc = 1;
- goto meta_command_exit;
- }
- open_db(p, 0);
- if( booleanValue(azArg[1]) ){
- sqlite3_set_authorizer(p->db, shellAuth, p);
- }else{
- sqlite3_set_authorizer(p->db, 0, 0);
- }
- }else
-#endif
-
- if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
- || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
- ){
- const char *zDestFile = 0;
- const char *zDb = 0;
- sqlite3 *pDest;
- sqlite3_backup *pBackup;
- int j;
- for(j=1; j<nArg; j++){
- const char *z = azArg[j];
- if( z[0]=='-' ){
- while( z[0]=='-' ) z++;
- /* No options to process at this time */
- {
- utf8_printf(stderr, "unknown option: %s\n", azArg[j]);
- return 1;
- }
- }else if( zDestFile==0 ){
- zDestFile = azArg[j];
- }else if( zDb==0 ){
- zDb = zDestFile;
- zDestFile = azArg[j];
- }else{
- raw_printf(stderr, "too many arguments to .backup\n");
- return 1;
- }
- }
- if( zDestFile==0 ){
- raw_printf(stderr, "missing FILENAME argument on .backup\n");
- return 1;
- }
- if( zDb==0 ) zDb = "main";
- rc = sqlite3_open(zDestFile, &pDest);
- if( rc!=SQLITE_OK ){
- utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
- sqlite3_close(pDest);
- return 1;
- }
- open_db(p, 0);
- pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
- if( pBackup==0 ){
- utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
- sqlite3_close(pDest);
- return 1;
- }
- while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
- sqlite3_backup_finish(pBackup);
- if( rc==SQLITE_DONE ){
- rc = 0;
- }else{
- utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
- rc = 1;
- }
- sqlite3_close(pDest);
- }else
-
- if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){
- if( nArg==2 ){
- bail_on_error = booleanValue(azArg[1]);
- }else{
- raw_printf(stderr, "Usage: .bail on|off\n");
- rc = 1;
- }
- }else
-
- if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){
- if( nArg==2 ){
- if( booleanValue(azArg[1]) ){
- setBinaryMode(p->out, 1);
- }else{
- setTextMode(p->out, 1);
- }
- }else{
- raw_printf(stderr, "Usage: .binary on|off\n");
- rc = 1;
- }
- }else
-
- if( c=='c' && strcmp(azArg[0],"cd")==0 ){
- if( nArg==2 ){
-#if defined(_WIN32) || defined(WIN32)
- wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
- rc = !SetCurrentDirectoryW(z);
- sqlite3_free(z);
-#else
- rc = chdir(azArg[1]);
-#endif
- if( rc ){
- utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
- rc = 1;
- }
- }else{
- raw_printf(stderr, "Usage: .cd DIRECTORY\n");
- rc = 1;
- }
- }else
-
- /* The undocumented ".breakpoint" command causes a call to the no-op
- ** routine named test_breakpoint().
- */
- if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
- test_breakpoint();
- }else
-
- if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){
- if( nArg==2 ){
- setOrClearFlag(p, SHFLG_CountChanges, azArg[1]);
- }else{
- raw_printf(stderr, "Usage: .changes on|off\n");
- rc = 1;
- }
- }else
-
- /* Cancel output redirection, if it is currently set (by .testcase)
- ** Then read the content of the testcase-out.txt file and compare against
- ** azArg[1]. If there are differences, report an error and exit.
- */
- if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
- char *zRes = 0;
- output_reset(p);
- if( nArg!=2 ){
- raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
- rc = 2;
- }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
- raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
- rc = 2;
- }else if( testcase_glob(azArg[1],zRes)==0 ){
- utf8_printf(stderr,
- "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
- p->zTestcase, azArg[1], zRes);
- rc = 2;
- }else{
- utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
- p->nCheck++;
- }
- sqlite3_free(zRes);
- }else
-
- if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
- if( nArg==2 ){
- tryToClone(p, azArg[1]);
- }else{
- raw_printf(stderr, "Usage: .clone FILENAME\n");
- rc = 1;
- }
- }else
-
- if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
- ShellState data;
- char *zErrMsg = 0;
- open_db(p, 0);
- memcpy(&data, p, sizeof(data));
- data.showHeader = 0;
- data.cMode = data.mode = MODE_List;
- sqlite3_snprintf(sizeof(data.colSeparator),data.colSeparator,": ");
- data.cnt = 0;
- sqlite3_exec(p->db, "SELECT name, file FROM pragma_database_list",
- callback, &data, &zErrMsg);
- if( zErrMsg ){
- utf8_printf(stderr,"Error: %s\n", zErrMsg);
- sqlite3_free(zErrMsg);
- rc = 1;
- }
- }else
-
- if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){
- rc = shell_dbinfo_command(p, nArg, azArg);
- }else
-
- if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
- const char *zLike = 0;
- int i;
- int savedShowHeader = p->showHeader;
- ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines);
- for(i=1; i<nArg; i++){
- if( azArg[i][0]=='-' ){
- const char *z = azArg[i]+1;
- if( z[0]=='-' ) z++;
- if( strcmp(z,"preserve-rowids")==0 ){
-#ifdef SQLITE_OMIT_VIRTUALTABLE
- raw_printf(stderr, "The --preserve-rowids option is not compatible"
- " with SQLITE_OMIT_VIRTUALTABLE\n");
- rc = 1;
- goto meta_command_exit;
-#else
- ShellSetFlag(p, SHFLG_PreserveRowid);
-#endif
- }else
- if( strcmp(z,"newlines")==0 ){
- ShellSetFlag(p, SHFLG_Newlines);
- }else
- {
- raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
- rc = 1;
- goto meta_command_exit;
- }
- }else if( zLike ){
- raw_printf(stderr, "Usage: .dump ?--preserve-rowids? "
- "?--newlines? ?LIKE-PATTERN?\n");
- rc = 1;
- goto meta_command_exit;
- }else{
- zLike = azArg[i];
- }
- }
- open_db(p, 0);
- /* When playing back a "dump", the content might appear in an order
- ** which causes immediate foreign key constraints to be violated.
- ** So disable foreign-key constraint enforcement to prevent problems. */
- raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
- raw_printf(p->out, "BEGIN TRANSACTION;\n");
- p->writableSchema = 0;
- p->showHeader = 0;
- /* Set writable_schema=ON since doing so forces SQLite to initialize
- ** as much of the schema as it can even if the sqlite_master table is
- ** corrupt. */
- sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
- p->nErr = 0;
- if( zLike==0 ){
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
- );
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE name=='sqlite_sequence'"
- );
- run_table_dump_query(p,
- "SELECT sql FROM sqlite_master "
- "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
- );
- }else{
- char *zSql;
- zSql = sqlite3_mprintf(
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE tbl_name LIKE %Q AND type=='table'"
- " AND sql NOT NULL", zLike);
- run_schema_dump_query(p,zSql);
- sqlite3_free(zSql);
- zSql = sqlite3_mprintf(
- "SELECT sql FROM sqlite_master "
- "WHERE sql NOT NULL"
- " AND type IN ('index','trigger','view')"
- " AND tbl_name LIKE %Q", zLike);
- run_table_dump_query(p, zSql, 0);
- sqlite3_free(zSql);
- }
- if( p->writableSchema ){
- raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
- p->writableSchema = 0;
- }
- sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
- sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
- raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
- p->showHeader = savedShowHeader;
- }else
-
- if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
- if( nArg==2 ){
- setOrClearFlag(p, SHFLG_Echo, azArg[1]);
- }else{
- raw_printf(stderr, "Usage: .echo on|off\n");
- rc = 1;
- }
- }else
-
- if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
- if( nArg==2 ){
- if( strcmp(azArg[1],"full")==0 ){
- p->autoEQP = 2;
- }else{
- p->autoEQP = booleanValue(azArg[1]);
- }
- }else{
- raw_printf(stderr, "Usage: .eqp on|off|full\n");
- rc = 1;
- }
- }else
-
- if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
- if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
- rc = 2;
- }else
-
- /* The ".explain" command is automatic now. It is largely pointless. It
- ** retained purely for backwards compatibility */
- if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
- int val = 1;
- if( nArg>=2 ){
- if( strcmp(azArg[1],"auto")==0 ){
- val = 99;
- }else{
- val = booleanValue(azArg[1]);
- }
- }
- if( val==1 && p->mode!=MODE_Explain ){
- p->normalMode = p->mode;
- p->mode = MODE_Explain;
- p->autoExplain = 0;
- }else if( val==0 ){
- if( p->mode==MODE_Explain ) p->mode = p->normalMode;
- p->autoExplain = 0;
- }else if( val==99 ){
- if( p->mode==MODE_Explain ) p->mode = p->normalMode;
- p->autoExplain = 1;
- }
- }else
-
- if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){
- ShellState data;
- char *zErrMsg = 0;
- int doStats = 0;
- memcpy(&data, p, sizeof(data));
- data.showHeader = 0;
- data.cMode = data.mode = MODE_Semi;
- if( nArg==2 && optionMatch(azArg[1], "indent") ){
- data.cMode = data.mode = MODE_Pretty;
- nArg = 1;
- }
- if( nArg!=1 ){
- raw_printf(stderr, "Usage: .fullschema ?--indent?\n");
- rc = 1;
- goto meta_command_exit;
- }
- open_db(p, 0);
- rc = sqlite3_exec(p->db,
- "SELECT sql FROM"
- " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
- " FROM sqlite_master UNION ALL"
- " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
- "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
- "ORDER BY rowid",
- callback, &data, &zErrMsg
- );
- if( rc==SQLITE_OK ){
- sqlite3_stmt *pStmt;
- rc = sqlite3_prepare_v2(p->db,
- "SELECT rowid FROM sqlite_master"
- " WHERE name GLOB 'sqlite_stat[134]'",
- -1, &pStmt, 0);
- doStats = sqlite3_step(pStmt)==SQLITE_ROW;
- sqlite3_finalize(pStmt);
- }
- if( doStats==0 ){
- raw_printf(p->out, "/* No STAT tables available */\n");
- }else{
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
- sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'",
- callback, &data, &zErrMsg);
- data.cMode = data.mode = MODE_Insert;
- data.zDestTable = "sqlite_stat1";
- shell_exec(p->db, "SELECT * FROM sqlite_stat1",
- shell_callback, &data,&zErrMsg);
- data.zDestTable = "sqlite_stat3";
- shell_exec(p->db, "SELECT * FROM sqlite_stat3",
- shell_callback, &data,&zErrMsg);
- data.zDestTable = "sqlite_stat4";
- shell_exec(p->db, "SELECT * FROM sqlite_stat4",
- shell_callback, &data, &zErrMsg);
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
- }
- }else
-
- if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){
- if( nArg==2 ){
- p->showHeader = booleanValue(azArg[1]);
- }else{
- raw_printf(stderr, "Usage: .headers on|off\n");
- rc = 1;
- }
- }else
-
- if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
- utf8_printf(p->out, "%s", zHelp);
- }else
-
- if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
- char *zTable; /* Insert data into this table */
- char *zFile; /* Name of file to extra content from */
- sqlite3_stmt *pStmt = NULL; /* A statement */
- int nCol; /* Number of columns in the table */
- int nByte; /* Number of bytes in an SQL string */
- int i, j; /* Loop counters */
- int needCommit; /* True to COMMIT or ROLLBACK at end */
- int nSep; /* Number of bytes in p->colSeparator[] */
- char *zSql; /* An SQL statement */
- ImportCtx sCtx; /* Reader context */
- char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
- int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */
-
- if( nArg!=3 ){
- raw_printf(stderr, "Usage: .import FILE TABLE\n");
- goto meta_command_exit;
- }
- zFile = azArg[1];
- zTable = azArg[2];
- seenInterrupt = 0;
- memset(&sCtx, 0, sizeof(sCtx));
- open_db(p, 0);
- nSep = strlen30(p->colSeparator);
- if( nSep==0 ){
- raw_printf(stderr,
- "Error: non-null column separator required for import\n");
- return 1;
- }
- if( nSep>1 ){
- raw_printf(stderr, "Error: multi-character column separators not allowed"
- " for import\n");
- return 1;
- }
- nSep = strlen30(p->rowSeparator);
- if( nSep==0 ){
- raw_printf(stderr, "Error: non-null row separator required for import\n");
- return 1;
- }
- if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
- /* When importing CSV (only), if the row separator is set to the
- ** default output row separator, change it to the default input
- ** row separator. This avoids having to maintain different input
- ** and output row separators. */
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- nSep = strlen30(p->rowSeparator);
- }
- if( nSep>1 ){
- raw_printf(stderr, "Error: multi-character row separators not allowed"
- " for import\n");
- return 1;
- }
- sCtx.zFile = zFile;
- sCtx.nLine = 1;
- if( sCtx.zFile[0]=='|' ){
-#ifdef SQLITE_OMIT_POPEN
- raw_printf(stderr, "Error: pipes are not supported in this OS\n");
- return 1;
-#else
- sCtx.in = popen(sCtx.zFile+1, "r");
- sCtx.zFile = "<pipe>";
- xCloser = pclose;
-#endif
- }else{
- sCtx.in = fopen(sCtx.zFile, "rb");
- xCloser = fclose;
- }
- if( p->mode==MODE_Ascii ){
- xRead = ascii_read_one_field;
- }else{
- xRead = csv_read_one_field;
- }
- if( sCtx.in==0 ){
- utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
- return 1;
- }
- sCtx.cColSep = p->colSeparator[0];
- sCtx.cRowSep = p->rowSeparator[0];
- zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
- if( zSql==0 ){
- raw_printf(stderr, "Error: out of memory\n");
- xCloser(sCtx.in);
- return 1;
- }
- nByte = strlen30(zSql);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */
- if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){
- char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
- char cSep = '(';
- while( xRead(&sCtx) ){
- zCreate = sqlite3_mprintf("%z%c\n \"%w\" TEXT", zCreate, cSep, sCtx.z);
- cSep = ',';
- if( sCtx.cTerm!=sCtx.cColSep ) break;
- }
- if( cSep=='(' ){
- sqlite3_free(zCreate);
- sqlite3_free(sCtx.z);
- xCloser(sCtx.in);
- utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
- return 1;
- }
- zCreate = sqlite3_mprintf("%z\n)", zCreate);
- rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
- sqlite3_free(zCreate);
- if( rc ){
- utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
- sqlite3_errmsg(p->db));
- sqlite3_free(sCtx.z);
- xCloser(sCtx.in);
- return 1;
- }
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- }
- sqlite3_free(zSql);
- if( rc ){
- if (pStmt) sqlite3_finalize(pStmt);
- utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
- xCloser(sCtx.in);
- return 1;
- }
- nCol = sqlite3_column_count(pStmt);
- sqlite3_finalize(pStmt);
- pStmt = 0;
- if( nCol==0 ) return 0; /* no columns, no error */
- zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
- if( zSql==0 ){
- raw_printf(stderr, "Error: out of memory\n");
- xCloser(sCtx.in);
- return 1;
- }
- sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
- j = strlen30(zSql);
- for(i=1; i<nCol; i++){
- zSql[j++] = ',';
- zSql[j++] = '?';
- }
- zSql[j++] = ')';
- zSql[j] = 0;
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- sqlite3_free(zSql);
- if( rc ){
- utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
- if (pStmt) sqlite3_finalize(pStmt);
- xCloser(sCtx.in);
- return 1;
- }
- needCommit = sqlite3_get_autocommit(p->db);
- if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
- do{
- int startLine = sCtx.nLine;
- for(i=0; i<nCol; i++){
- char *z = xRead(&sCtx);
- /*
- ** Did we reach end-of-file before finding any columns?
- ** If so, stop instead of NULL filling the remaining columns.
- */
- if( z==0 && i==0 ) break;
- /*
- ** Did we reach end-of-file OR end-of-line before finding any
- ** columns in ASCII mode? If so, stop instead of NULL filling
- ** the remaining columns.
- */
- if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
- sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
- if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
- utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
- "filling the rest with NULL\n",
- sCtx.zFile, startLine, nCol, i+1);
- i += 2;
- while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
- }
- }
- if( sCtx.cTerm==sCtx.cColSep ){
- do{
- xRead(&sCtx);
- i++;
- }while( sCtx.cTerm==sCtx.cColSep );
- utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
- "extras ignored\n",
- sCtx.zFile, startLine, nCol, i);
- }
- if( i>=nCol ){
- sqlite3_step(pStmt);
- rc = sqlite3_reset(pStmt);
- if( rc!=SQLITE_OK ){
- utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
- startLine, sqlite3_errmsg(p->db));
- }
- }
- }while( sCtx.cTerm!=EOF );
-
- xCloser(sCtx.in);
- sqlite3_free(sCtx.z);
- sqlite3_finalize(pStmt);
- if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
- }else
-
-#ifndef SQLITE_UNTESTABLE
- if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
- char *zSql;
- char *zCollist = 0;
- sqlite3_stmt *pStmt;
- int tnum = 0;
- int i;
- if( nArg!=3 ){
- utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n");
- rc = 1;
- goto meta_command_exit;
- }
- open_db(p, 0);
- zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_master"
- " WHERE name='%q' AND type='index'", azArg[1]);
- sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- sqlite3_free(zSql);
- if( sqlite3_step(pStmt)==SQLITE_ROW ){
- tnum = sqlite3_column_int(pStmt, 0);
- }
- sqlite3_finalize(pStmt);
- if( tnum==0 ){
- utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]);
- rc = 1;
- goto meta_command_exit;
- }
- zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- sqlite3_free(zSql);
- i = 0;
- while( sqlite3_step(pStmt)==SQLITE_ROW ){
- char zLabel[20];
- const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
- i++;
- if( zCol==0 ){
- if( sqlite3_column_int(pStmt,1)==-1 ){
- zCol = "_ROWID_";
- }else{
- sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i);
- zCol = zLabel;
- }
- }
- if( zCollist==0 ){
- zCollist = sqlite3_mprintf("\"%w\"", zCol);
- }else{
- zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
- }
- }
- sqlite3_finalize(pStmt);
- zSql = sqlite3_mprintf(
- "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%s))WITHOUT ROWID",
- azArg[2], zCollist, zCollist);
- sqlite3_free(zCollist);
- rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
- if( rc==SQLITE_OK ){
- rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
- sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
- if( rc ){
- utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
- }else{
- utf8_printf(stdout, "%s;\n", zSql);
- raw_printf(stdout,
- "WARNING: writing to an imposter table will corrupt the index!\n"
- );
- }
- }else{
- raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
- rc = 1;
- }
- sqlite3_free(zSql);
- }else
-#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
-
-#ifdef SQLITE_ENABLE_IOTRACE
- if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
- SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
- if( iotrace && iotrace!=stdout ) fclose(iotrace);
- iotrace = 0;
- if( nArg<2 ){
- sqlite3IoTrace = 0;
- }else if( strcmp(azArg[1], "-")==0 ){
- sqlite3IoTrace = iotracePrintf;
- iotrace = stdout;
- }else{
- iotrace = fopen(azArg[1], "w");
- if( iotrace==0 ){
- utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
- sqlite3IoTrace = 0;
- rc = 1;
- }else{
- sqlite3IoTrace = iotracePrintf;
- }
- }
- }else
-#endif
-
- if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){
- static const struct {
- const char *zLimitName; /* Name of a limit */
- int limitCode; /* Integer code for that limit */
- } aLimit[] = {
- { "length", SQLITE_LIMIT_LENGTH },
- { "sql_length", SQLITE_LIMIT_SQL_LENGTH },
- { "column", SQLITE_LIMIT_COLUMN },
- { "expr_depth", SQLITE_LIMIT_EXPR_DEPTH },
- { "compound_select", SQLITE_LIMIT_COMPOUND_SELECT },
- { "vdbe_op", SQLITE_LIMIT_VDBE_OP },
- { "function_arg", SQLITE_LIMIT_FUNCTION_ARG },
- { "attached", SQLITE_LIMIT_ATTACHED },
- { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH },
- { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER },
- { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH },
- { "worker_threads", SQLITE_LIMIT_WORKER_THREADS },
- };
- int i, n2;
- open_db(p, 0);
- if( nArg==1 ){
- for(i=0; i<ArraySize(aLimit); i++){
- printf("%20s %d\n", aLimit[i].zLimitName,
- sqlite3_limit(p->db, aLimit[i].limitCode, -1));
- }
- }else if( nArg>3 ){
- raw_printf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n");
- rc = 1;
- goto meta_command_exit;
- }else{
- int iLimit = -1;
- n2 = strlen30(azArg[1]);
- for(i=0; i<ArraySize(aLimit); i++){
- if( sqlite3_strnicmp(aLimit[i].zLimitName, azArg[1], n2)==0 ){
- if( iLimit<0 ){
- iLimit = i;
- }else{
- utf8_printf(stderr, "ambiguous limit: \"%s\"\n", azArg[1]);
- rc = 1;
- goto meta_command_exit;
- }
- }
- }
- if( iLimit<0 ){
- utf8_printf(stderr, "unknown limit: \"%s\"\n"
- "enter \".limits\" with no arguments for a list.\n",
- azArg[1]);
- rc = 1;
- goto meta_command_exit;
- }
- if( nArg==3 ){
- sqlite3_limit(p->db, aLimit[iLimit].limitCode,
- (int)integerValue(azArg[2]));
- }
- printf("%20s %d\n", aLimit[iLimit].zLimitName,
- sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1));
- }
- }else
-
- if( c=='l' && n>2 && strncmp(azArg[0], "lint", n)==0 ){
- open_db(p, 0);
- lintDotCommand(p, azArg, nArg);
- }else
-
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
- if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
- const char *zFile, *zProc;
- char *zErrMsg = 0;
- if( nArg<2 ){
- raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
- rc = 1;
- goto meta_command_exit;
- }
- zFile = azArg[1];
- zProc = nArg>=3 ? azArg[2] : 0;
- open_db(p, 0);
- rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
- if( rc!=SQLITE_OK ){
- utf8_printf(stderr, "Error: %s\n", zErrMsg);
- sqlite3_free(zErrMsg);
- rc = 1;
- }
- }else
-#endif
-
- if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
- if( nArg!=2 ){
- raw_printf(stderr, "Usage: .log FILENAME\n");
- rc = 1;
- }else{
- const char *zFile = azArg[1];
- output_file_close(p->pLog);
- p->pLog = output_file_open(zFile);
- }
- }else
-
- if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
- const char *zMode = nArg>=2 ? azArg[1] : "";
- int n2 = (int)strlen(zMode);
- int c2 = zMode[0];
- if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
- p->mode = MODE_Line;
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
- p->mode = MODE_Column;
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
- p->mode = MODE_List;
- sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
- p->mode = MODE_Html;
- }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
- p->mode = MODE_Tcl;
- sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
- p->mode = MODE_Csv;
- sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
- }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
- p->mode = MODE_List;
- sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
- }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
- p->mode = MODE_Insert;
- set_table_name(p, nArg>=3 ? azArg[2] : "table");
- }else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){
- p->mode = MODE_Quote;
- }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
- p->mode = MODE_Ascii;
- sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
- }else if( nArg==1 ){
- raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
- }else{
- raw_printf(stderr, "Error: mode should be one of: "
- "ascii column csv html insert line list quote tabs tcl\n");
- rc = 1;
- }
- p->cMode = p->mode;
- }else
-
- if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
- if( nArg==2 ){
- sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
- "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
- }else{
- raw_printf(stderr, "Usage: .nullvalue STRING\n");
- rc = 1;
- }
- }else
-
- if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
- char *zNewFilename; /* Name of the database file to open */
- int iName = 1; /* Index in azArg[] of the filename */
- int newFlag = 0; /* True to delete file before opening */
- /* Close the existing database */
- session_close_all(p);
- sqlite3_close(p->db);
- p->db = 0;
- p->zDbFilename = 0;
- sqlite3_free(p->zFreeOnClose);
- p->zFreeOnClose = 0;
- /* Check for command-line arguments */
- for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){
- const char *z = azArg[iName];
- if( optionMatch(z,"new") ){
- newFlag = 1;
- }else if( z[0]=='-' ){
- utf8_printf(stderr, "unknown option: %s\n", z);
- rc = 1;
- goto meta_command_exit;
- }
- }
- /* If a filename is specified, try to open it first */
- zNewFilename = nArg>iName ? sqlite3_mprintf("%s", azArg[iName]) : 0;
- if( zNewFilename ){
- if( newFlag ) shellDeleteFile(zNewFilename);
- p->zDbFilename = zNewFilename;
- open_db(p, 1);
- if( p->db==0 ){
- utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename);
- sqlite3_free(zNewFilename);
- }else{
- p->zFreeOnClose = zNewFilename;
- }
- }
- if( p->db==0 ){
- /* As a fall-back open a TEMP database */
- p->zDbFilename = 0;
- open_db(p, 0);
- }
- }else
-
- if( c=='o'
- && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0)
- ){
- const char *zFile = nArg>=2 ? azArg[1] : "stdout";
- if( nArg>2 ){
- utf8_printf(stderr, "Usage: .%s FILE\n", azArg[0]);
- rc = 1;
- goto meta_command_exit;
- }
- if( n>1 && strncmp(azArg[0], "once", n)==0 ){
- if( nArg<2 ){
- raw_printf(stderr, "Usage: .once FILE\n");
- rc = 1;
- goto meta_command_exit;
- }
- p->outCount = 2;
- }else{
- p->outCount = 0;
- }
- output_reset(p);
- if( zFile[0]=='|' ){
-#ifdef SQLITE_OMIT_POPEN
- raw_printf(stderr, "Error: pipes are not supported in this OS\n");
- rc = 1;
- p->out = stdout;
-#else
- p->out = popen(zFile + 1, "w");
- if( p->out==0 ){
- utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
- p->out = stdout;
- rc = 1;
- }else{
- sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
- }
-#endif
- }else{
- p->out = output_file_open(zFile);
- if( p->out==0 ){
- if( strcmp(zFile,"off")!=0 ){
- utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
- }
- p->out = stdout;
- rc = 1;
- } else {
- sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
- }
- }
- }else
-
- if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){
- int i;
- for(i=1; i<nArg; i++){
- if( i>1 ) raw_printf(p->out, " ");
- utf8_printf(p->out, "%s", azArg[i]);
- }
- raw_printf(p->out, "\n");
- }else
-
- if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){
- if( nArg >= 2) {
- strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
- }
- if( nArg >= 3) {
- strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
- }
- }else
-
- if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
- rc = 2;
- }else
-
- if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
- FILE *alt;
- if( nArg!=2 ){
- raw_printf(stderr, "Usage: .read FILE\n");
- rc = 1;
- goto meta_command_exit;
- }
- alt = fopen(azArg[1], "rb");
- if( alt==0 ){
- utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
- rc = 1;
- }else{
- rc = process_input(p, alt);
- fclose(alt);
- }
- }else
-
- if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
- const char *zSrcFile;
- const char *zDb;
- sqlite3 *pSrc;
- sqlite3_backup *pBackup;
- int nTimeout = 0;
-
- if( nArg==2 ){
- zSrcFile = azArg[1];
- zDb = "main";
- }else if( nArg==3 ){
- zSrcFile = azArg[2];
- zDb = azArg[1];
- }else{
- raw_printf(stderr, "Usage: .restore ?DB? FILE\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_open(zSrcFile, &pSrc);
- if( rc!=SQLITE_OK ){
- utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
- sqlite3_close(pSrc);
- return 1;
- }
- open_db(p, 0);
- pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
- if( pBackup==0 ){
- utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
- sqlite3_close(pSrc);
- return 1;
- }
- while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
- || rc==SQLITE_BUSY ){
- if( rc==SQLITE_BUSY ){
- if( nTimeout++ >= 3 ) break;
- sqlite3_sleep(100);
- }
- }
- sqlite3_backup_finish(pBackup);
- if( rc==SQLITE_DONE ){
- rc = 0;
- }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
- raw_printf(stderr, "Error: source database is busy\n");
- rc = 1;
- }else{
- utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
- rc = 1;
- }
- sqlite3_close(pSrc);
- }else
-
-
- if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
- if( nArg==2 ){
- p->scanstatsOn = booleanValue(azArg[1]);
-#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
- raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
-#endif
- }else{
- raw_printf(stderr, "Usage: .scanstats on|off\n");
- rc = 1;
- }
- }else
-
- if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
- ShellText sSelect;
- ShellState data;
- char *zErrMsg = 0;
- const char *zDiv = 0;
- int iSchema = 0;
-
- open_db(p, 0);
- memcpy(&data, p, sizeof(data));
- data.showHeader = 0;
- data.cMode = data.mode = MODE_Semi;
- initText(&sSelect);
- if( nArg>=2 && optionMatch(azArg[1], "indent") ){
- data.cMode = data.mode = MODE_Pretty;
- nArg--;
- if( nArg==2 ) azArg[1] = azArg[2];
- }
- if( nArg==2 && azArg[1][0]!='-' ){
- int i;
- for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
- if( strcmp(azArg[1],"sqlite_master")==0 ){
- char *new_argv[2], *new_colv[2];
- new_argv[0] = "CREATE TABLE sqlite_master (\n"
- " type text,\n"
- " name text,\n"
- " tbl_name text,\n"
- " rootpage integer,\n"
- " sql text\n"
- ")";
- new_argv[1] = 0;
- new_colv[0] = "sql";
- new_colv[1] = 0;
- callback(&data, 1, new_argv, new_colv);
- rc = SQLITE_OK;
- }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
- char *new_argv[2], *new_colv[2];
- new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
- " type text,\n"
- " name text,\n"
- " tbl_name text,\n"
- " rootpage integer,\n"
- " sql text\n"
- ")";
- new_argv[1] = 0;
- new_colv[0] = "sql";
- new_colv[1] = 0;
- callback(&data, 1, new_argv, new_colv);
- rc = SQLITE_OK;
- }else{
- zDiv = "(";
- }
- }else if( nArg==1 ){
- zDiv = "(";
- }else{
- raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
- rc = 1;
- goto meta_command_exit;
- }
- if( zDiv ){
- sqlite3_stmt *pStmt = 0;
- rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
- -1, &pStmt, 0);
- if( rc ){
- utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
- sqlite3_finalize(pStmt);
- rc = 1;
- goto meta_command_exit;
- }
- appendText(&sSelect, "SELECT sql FROM", 0);
- iSchema = 0;
- while( sqlite3_step(pStmt)==SQLITE_ROW ){
- const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
- char zScNum[30];
- sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
- appendText(&sSelect, zDiv, 0);
- zDiv = " UNION ALL ";
- if( strcmp(zDb, "main")!=0 ){
- appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
- appendText(&sSelect, zDb, '"');
- appendText(&sSelect, ") AS sql, type, tbl_name, name, rowid,", 0);
- appendText(&sSelect, zScNum, 0);
- appendText(&sSelect, " AS snum, ", 0);
- appendText(&sSelect, zDb, '\'');
- appendText(&sSelect, " AS sname FROM ", 0);
- appendText(&sSelect, zDb, '"');
- appendText(&sSelect, ".sqlite_master", 0);
- }else{
- appendText(&sSelect, "SELECT sql, type, tbl_name, name, rowid, ", 0);
- appendText(&sSelect, zScNum, 0);
- appendText(&sSelect, " AS snum, 'main' AS sname FROM sqlite_master",0);
- }
- }
- sqlite3_finalize(pStmt);
- appendText(&sSelect, ") WHERE ", 0);
- if( nArg>1 ){
- char *zQarg = sqlite3_mprintf("%Q", azArg[1]);
- if( strchr(azArg[1], '.') ){
- appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
- }else{
- appendText(&sSelect, "lower(tbl_name)", 0);
- }
- appendText(&sSelect, strchr(azArg[1], '*') ? " GLOB " : " LIKE ", 0);
- appendText(&sSelect, zQarg, 0);
- appendText(&sSelect, " AND ", 0);
- sqlite3_free(zQarg);
- }
- appendText(&sSelect, "type!='meta' AND sql IS NOT NULL"
- " ORDER BY snum, rowid", 0);
- rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
- freeText(&sSelect);
- }
- if( zErrMsg ){
- utf8_printf(stderr,"Error: %s\n", zErrMsg);
- sqlite3_free(zErrMsg);
- rc = 1;
- }else if( rc != SQLITE_OK ){
- raw_printf(stderr,"Error: querying schema information\n");
- rc = 1;
- }else{
- rc = 0;
- }
- }else
-
-#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
- if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
- sqlite3SelectTrace = (int)integerValue(azArg[1]);
- }else
-#endif
-
-#if defined(SQLITE_ENABLE_SESSION)
- if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){
- OpenSession *pSession = &p->aSession[0];
- char **azCmd = &azArg[1];
- int iSes = 0;
- int nCmd = nArg - 1;
- int i;
- if( nArg<=1 ) goto session_syntax_error;
- open_db(p, 0);
- if( nArg>=3 ){
- for(iSes=0; iSes<p->nSession; iSes++){
- if( strcmp(p->aSession[iSes].zName, azArg[1])==0 ) break;
- }
- if( iSes<p->nSession ){
- pSession = &p->aSession[iSes];
- azCmd++;
- nCmd--;
- }else{
- pSession = &p->aSession[0];
- iSes = 0;
- }
- }
-
- /* .session attach TABLE
- ** Invoke the sqlite3session_attach() interface to attach a particular
- ** table so that it is never filtered.
- */
- if( strcmp(azCmd[0],"attach")==0 ){
- if( nCmd!=2 ) goto session_syntax_error;
- if( pSession->p==0 ){
- session_not_open:
- raw_printf(stderr, "ERROR: No sessions are open\n");
- }else{
- rc = sqlite3session_attach(pSession->p, azCmd[1]);
- if( rc ){
- raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc);
- rc = 0;
- }
- }
- }else
-
- /* .session changeset FILE
- ** .session patchset FILE
- ** Write a changeset or patchset into a file. The file is overwritten.
- */
- if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){
- FILE *out = 0;
- if( nCmd!=2 ) goto session_syntax_error;
- if( pSession->p==0 ) goto session_not_open;
- out = fopen(azCmd[1], "wb");
- if( out==0 ){
- utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", azCmd[1]);
- }else{
- int szChng;
- void *pChng;
- if( azCmd[0][0]=='c' ){
- rc = sqlite3session_changeset(pSession->p, &szChng, &pChng);
- }else{
- rc = sqlite3session_patchset(pSession->p, &szChng, &pChng);
- }
- if( rc ){
- printf("Error: error code %d\n", rc);
- rc = 0;
- }
- if( pChng
- && fwrite(pChng, szChng, 1, out)!=1 ){
- raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n",
- szChng);
- }
- sqlite3_free(pChng);
- fclose(out);
- }
- }else
-
- /* .session close
- ** Close the identified session
- */
- if( strcmp(azCmd[0], "close")==0 ){
- if( nCmd!=1 ) goto session_syntax_error;
- if( p->nSession ){
- session_close(pSession);
- p->aSession[iSes] = p->aSession[--p->nSession];
- }
- }else
-
- /* .session enable ?BOOLEAN?
- ** Query or set the enable flag
- */
- if( strcmp(azCmd[0], "enable")==0 ){
- int ii;
- if( nCmd>2 ) goto session_syntax_error;
- ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
- if( p->nSession ){
- ii = sqlite3session_enable(pSession->p, ii);
- utf8_printf(p->out, "session %s enable flag = %d\n",
- pSession->zName, ii);
- }
- }else
-
- /* .session filter GLOB ....
- ** Set a list of GLOB patterns of table names to be excluded.
- */
- if( strcmp(azCmd[0], "filter")==0 ){
- int ii, nByte;
- if( nCmd<2 ) goto session_syntax_error;
- if( p->nSession ){
- for(ii=0; ii<pSession->nFilter; ii++){
- sqlite3_free(pSession->azFilter[ii]);
- }
- sqlite3_free(pSession->azFilter);
- nByte = sizeof(pSession->azFilter[0])*(nCmd-1);
- pSession->azFilter = sqlite3_malloc( nByte );
- if( pSession->azFilter==0 ){
- raw_printf(stderr, "Error: out or memory\n");
- exit(1);
- }
- for(ii=1; ii<nCmd; ii++){
- pSession->azFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]);
- }
- pSession->nFilter = ii-1;
- }
- }else
-
- /* .session indirect ?BOOLEAN?
- ** Query or set the indirect flag
- */
- if( strcmp(azCmd[0], "indirect")==0 ){
- int ii;
- if( nCmd>2 ) goto session_syntax_error;
- ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
- if( p->nSession ){
- ii = sqlite3session_indirect(pSession->p, ii);
- utf8_printf(p->out, "session %s indirect flag = %d\n",
- pSession->zName, ii);
- }
- }else
-
- /* .session isempty
- ** Determine if the session is empty
- */
- if( strcmp(azCmd[0], "isempty")==0 ){
- int ii;
- if( nCmd!=1 ) goto session_syntax_error;
- if( p->nSession ){
- ii = sqlite3session_isempty(pSession->p);
- utf8_printf(p->out, "session %s isempty flag = %d\n",
- pSession->zName, ii);
- }
- }else
-
- /* .session list
- ** List all currently open sessions
- */
- if( strcmp(azCmd[0],"list")==0 ){
- for(i=0; i<p->nSession; i++){
- utf8_printf(p->out, "%d %s\n", i, p->aSession[i].zName);
- }
- }else
-
- /* .session open DB NAME
- ** Open a new session called NAME on the attached database DB.
- ** DB is normally "main".
- */
- if( strcmp(azCmd[0],"open")==0 ){
- char *zName;
- if( nCmd!=3 ) goto session_syntax_error;
- zName = azCmd[2];
- if( zName[0]==0 ) goto session_syntax_error;
- for(i=0; i<p->nSession; i++){
- if( strcmp(p->aSession[i].zName,zName)==0 ){
- utf8_printf(stderr, "Session \"%s\" already exists\n", zName);
- goto meta_command_exit;
- }
- }
- if( p->nSession>=ArraySize(p->aSession) ){
- raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(p->aSession));
- goto meta_command_exit;
- }
- pSession = &p->aSession[p->nSession];
- rc = sqlite3session_create(p->db, azCmd[1], &pSession->p);
- if( rc ){
- raw_printf(stderr, "Cannot open session: error code=%d\n", rc);
- rc = 0;
- goto meta_command_exit;
- }
- pSession->nFilter = 0;
- sqlite3session_table_filter(pSession->p, session_filter, pSession);
- p->nSession++;
- pSession->zName = sqlite3_mprintf("%s", zName);
- }else
- /* If no command name matches, show a syntax error */
- session_syntax_error:
- session_help(p);
- }else
-#endif
-
-#ifdef SQLITE_DEBUG
- /* Undocumented commands for internal testing. Subject to change
- ** without notice. */
- if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){
- if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){
- int i, v;
- for(i=1; i<nArg; i++){
- v = booleanValue(azArg[i]);
- utf8_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
- }
- }
- if( strncmp(azArg[0]+9, "integer", n-9)==0 ){
- int i; sqlite3_int64 v;
- for(i=1; i<nArg; i++){
- char zBuf[200];
- v = integerValue(azArg[i]);
- sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
- utf8_printf(p->out, "%s", zBuf);
- }
- }
- }else
-#endif
-
- if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){
- int bIsInit = 0; /* True to initialize the SELFTEST table */
- int bVerbose = 0; /* Verbose output */
- int bSelftestExists; /* True if SELFTEST already exists */
- int i, k; /* Loop counters */
- int nTest = 0; /* Number of tests runs */
- int nErr = 0; /* Number of errors seen */
- ShellText str; /* Answer for a query */
- sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
-
- open_db(p,0);
- for(i=1; i<nArg; i++){
- const char *z = azArg[i];
- if( z[0]=='-' && z[1]=='-' ) z++;
- if( strcmp(z,"-init")==0 ){
- bIsInit = 1;
- }else
- if( strcmp(z,"-v")==0 ){
- bVerbose++;
- }else
- {
- utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
- azArg[i], azArg[0]);
- raw_printf(stderr, "Should be one of: --init -v\n");
- rc = 1;
- goto meta_command_exit;
- }
- }
- if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
- != SQLITE_OK ){
- bSelftestExists = 0;
- }else{
- bSelftestExists = 1;
- }
- if( bIsInit ){
- createSelftestTable(p);
- bSelftestExists = 1;
- }
- initText(&str);
- appendText(&str, "x", 0);
- for(k=bSelftestExists; k>=0; k--){
- if( k==1 ){
- rc = sqlite3_prepare_v2(p->db,
- "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
- -1, &pStmt, 0);
- }else{
- rc = sqlite3_prepare_v2(p->db,
- "VALUES(0,'memo','Missing SELFTEST table - default checks only',''),"
- " (1,'run','PRAGMA integrity_check','ok')",
- -1, &pStmt, 0);
- }
- if( rc ){
- raw_printf(stderr, "Error querying the selftest table\n");
- rc = 1;
- sqlite3_finalize(pStmt);
- goto meta_command_exit;
- }
- for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){
- int tno = sqlite3_column_int(pStmt, 0);
- const char *zOp = (const char*)sqlite3_column_text(pStmt, 1);
- const char *zSql = (const char*)sqlite3_column_text(pStmt, 2);
- const char *zAns = (const char*)sqlite3_column_text(pStmt, 3);
-
- k = 0;
- if( bVerbose>0 ){
- char *zQuote = sqlite3_mprintf("%q", zSql);
- printf("%d: %s %s\n", tno, zOp, zSql);
- sqlite3_free(zQuote);
- }
- if( strcmp(zOp,"memo")==0 ){
- utf8_printf(p->out, "%s\n", zSql);
- }else
- if( strcmp(zOp,"run")==0 ){
- char *zErrMsg = 0;
- str.n = 0;
- str.z[0] = 0;
- rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
- nTest++;
- if( bVerbose ){
- utf8_printf(p->out, "Result: %s\n", str.z);
- }
- if( rc || zErrMsg ){
- nErr++;
- rc = 1;
- utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
- sqlite3_free(zErrMsg);
- }else if( strcmp(zAns,str.z)!=0 ){
- nErr++;
- rc = 1;
- utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
- utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
- }
- }else
- {
- utf8_printf(stderr,
- "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
- rc = 1;
- break;
- }
- } /* End loop over rows of content from SELFTEST */
- sqlite3_finalize(pStmt);
- } /* End loop over k */
- freeText(&str);
- utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
- }else
-
- if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
- if( nArg<2 || nArg>3 ){
- raw_printf(stderr, "Usage: .separator COL ?ROW?\n");
- rc = 1;
- }
- if( nArg>=2 ){
- sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
- "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
- }
- if( nArg>=3 ){
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
- "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
- }
- }else
-
- if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){
- const char *zLike = 0; /* Which table to checksum. 0 means everything */
- int i; /* Loop counter */
- int bSchema = 0; /* Also hash the schema */
- int bSeparate = 0; /* Hash each table separately */
- int iSize = 224; /* Hash algorithm to use */
- int bDebug = 0; /* Only show the query that would have run */
- sqlite3_stmt *pStmt; /* For querying tables names */
- char *zSql; /* SQL to be run */
- char *zSep; /* Separator */
- ShellText sSql; /* Complete SQL for the query to run the hash */
- ShellText sQuery; /* Set of queries used to read all content */
- open_db(p, 0);
- for(i=1; i<nArg; i++){
- const char *z = azArg[i];
- if( z[0]=='-' ){
- z++;
- if( z[0]=='-' ) z++;
- if( strcmp(z,"schema")==0 ){
- bSchema = 1;
- }else
- if( strcmp(z,"sha3-224")==0 || strcmp(z,"sha3-256")==0
- || strcmp(z,"sha3-384")==0 || strcmp(z,"sha3-512")==0
- ){
- iSize = atoi(&z[5]);
- }else
- if( strcmp(z,"debug")==0 ){
- bDebug = 1;
- }else
- {
- utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
- azArg[i], azArg[0]);
- raw_printf(stderr, "Should be one of: --schema"
- " --sha3-224 --sha3-255 --sha3-384 --sha3-512\n");
- rc = 1;
- goto meta_command_exit;
- }
- }else if( zLike ){
- raw_printf(stderr, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n");
- rc = 1;
- goto meta_command_exit;
- }else{
- zLike = z;
- bSeparate = 1;
- if( sqlite3_strlike("sqlite_%", zLike, 0)==0 ) bSchema = 1;
- }
- }
- if( bSchema ){
- zSql = "SELECT lower(name) FROM sqlite_master"
- " WHERE type='table' AND coalesce(rootpage,0)>1"
- " UNION ALL SELECT 'sqlite_master'"
- " ORDER BY 1 collate nocase";
- }else{
- zSql = "SELECT lower(name) FROM sqlite_master"
- " WHERE type='table' AND coalesce(rootpage,0)>1"
- " AND name NOT LIKE 'sqlite_%'"
- " ORDER BY 1 collate nocase";
- }
- sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- initText(&sQuery);
- initText(&sSql);
- appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0);
- zSep = "VALUES(";
- while( SQLITE_ROW==sqlite3_step(pStmt) ){
- const char *zTab = (const char*)sqlite3_column_text(pStmt,0);
- if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue;
- if( strncmp(zTab, "sqlite_",7)!=0 ){
- appendText(&sQuery,"SELECT * FROM ", 0);
- appendText(&sQuery,zTab,'"');
- appendText(&sQuery," NOT INDEXED;", 0);
- }else if( strcmp(zTab, "sqlite_master")==0 ){
- appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_master"
- " ORDER BY name;", 0);
- }else if( strcmp(zTab, "sqlite_sequence")==0 ){
- appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence"
- " ORDER BY name;", 0);
- }else if( strcmp(zTab, "sqlite_stat1")==0 ){
- appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1"
- " ORDER BY tbl,idx;", 0);
- }else if( strcmp(zTab, "sqlite_stat3")==0
- || strcmp(zTab, "sqlite_stat4")==0 ){
- appendText(&sQuery, "SELECT * FROM ", 0);
- appendText(&sQuery, zTab, 0);
- appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0);
- }
- appendText(&sSql, zSep, 0);
- appendText(&sSql, sQuery.z, '\'');
- sQuery.n = 0;
- appendText(&sSql, ",", 0);
- appendText(&sSql, zTab, '\'');
- zSep = "),(";
- }
- sqlite3_finalize(pStmt);
- if( bSeparate ){
- zSql = sqlite3_mprintf(
- "%s))"
- " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label"
- " FROM [sha3sum$query]",
- sSql.z, iSize);
- }else{
- zSql = sqlite3_mprintf(
- "%s))"
- " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash"
- " FROM [sha3sum$query]",
- sSql.z, iSize);
- }
- freeText(&sQuery);
- freeText(&sSql);
- if( bDebug ){
- utf8_printf(p->out, "%s\n", zSql);
- }else{
- shell_exec(p->db, zSql, shell_callback, p, 0);
- }
- sqlite3_free(zSql);
- }else
-
- if( c=='s'
- && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
- ){
- char *zCmd;
- int i, x;
- if( nArg<2 ){
- raw_printf(stderr, "Usage: .system COMMAND\n");
- rc = 1;
- goto meta_command_exit;
- }
- zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
- for(i=2; i<nArg; i++){
- zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
- zCmd, azArg[i]);
- }
- x = system(zCmd);
- sqlite3_free(zCmd);
- if( x ) raw_printf(stderr, "System command returns %d\n", x);
- }else
-
- if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
- static const char *azBool[] = { "off", "on", "full", "unk" };
- int i;
- if( nArg!=1 ){
- raw_printf(stderr, "Usage: .show\n");
- rc = 1;
- goto meta_command_exit;
- }
- utf8_printf(p->out, "%12.12s: %s\n","echo",
- azBool[ShellHasFlag(p, SHFLG_Echo)]);
- utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
- utf8_printf(p->out, "%12.12s: %s\n","explain",
- p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
- utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
- utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
- utf8_printf(p->out, "%12.12s: ", "nullvalue");
- output_c_string(p->out, p->nullValue);
- raw_printf(p->out, "\n");
- utf8_printf(p->out,"%12.12s: %s\n","output",
- strlen30(p->outfile) ? p->outfile : "stdout");
- utf8_printf(p->out,"%12.12s: ", "colseparator");
- output_c_string(p->out, p->colSeparator);
- raw_printf(p->out, "\n");
- utf8_printf(p->out,"%12.12s: ", "rowseparator");
- output_c_string(p->out, p->rowSeparator);
- raw_printf(p->out, "\n");
- utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]);
- utf8_printf(p->out, "%12.12s: ", "width");
- for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
- raw_printf(p->out, "%d ", p->colWidth[i]);
- }
- raw_printf(p->out, "\n");
- utf8_printf(p->out, "%12.12s: %s\n", "filename",
- p->zDbFilename ? p->zDbFilename : "");
- }else
-
- if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
- if( nArg==2 ){
- p->statsOn = booleanValue(azArg[1]);
- }else if( nArg==1 ){
- display_stats(p->db, p, 0);
- }else{
- raw_printf(stderr, "Usage: .stats ?on|off?\n");
- rc = 1;
- }
- }else
-
- if( (c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0)
- || (c=='i' && (strncmp(azArg[0], "indices", n)==0
- || strncmp(azArg[0], "indexes", n)==0) )
- ){
- sqlite3_stmt *pStmt;
- char **azResult;
- int nRow, nAlloc;
- int ii;
- ShellText s;
- initText(&s);
- open_db(p, 0);
- rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
- if( rc ) return shellDatabaseError(p->db);
-
- if( nArg>2 && c=='i' ){
- /* It is an historical accident that the .indexes command shows an error
- ** when called with the wrong number of arguments whereas the .tables
- ** command does not. */
- raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
- rc = 1;
- goto meta_command_exit;
- }
- for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
- const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
- if( zDbName==0 ) continue;
- if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0);
- if( sqlite3_stricmp(zDbName, "main")==0 ){
- appendText(&s, "SELECT name FROM ", 0);
- }else{
- appendText(&s, "SELECT ", 0);
- appendText(&s, zDbName, '\'');
- appendText(&s, "||'.'||name FROM ", 0);
- }
- appendText(&s, zDbName, '"');
- appendText(&s, ".sqlite_master ", 0);
- if( c=='t' ){
- appendText(&s," WHERE type IN ('table','view')"
- " AND name NOT LIKE 'sqlite_%'"
- " AND name LIKE ?1", 0);
- }else{
- appendText(&s," WHERE type='index'"
- " AND tbl_name LIKE ?1", 0);
- }
- }
- rc = sqlite3_finalize(pStmt);
- appendText(&s, " ORDER BY 1", 0);
- rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);
- freeText(&s);
- if( rc ) return shellDatabaseError(p->db);
-
- /* Run the SQL statement prepared by the above block. Store the results
- ** as an array of nul-terminated strings in azResult[]. */
- nRow = nAlloc = 0;
- azResult = 0;
- if( nArg>1 ){
- sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT);
- }else{
- sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC);
- }
- while( sqlite3_step(pStmt)==SQLITE_ROW ){
- if( nRow>=nAlloc ){
- char **azNew;
- int n2 = nAlloc*2 + 10;
- azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
- if( azNew==0 ){
- rc = shellNomemError();
- break;
- }
- nAlloc = n2;
- azResult = azNew;
- }
- azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
- if( 0==azResult[nRow] ){
- rc = shellNomemError();
- break;
- }
- nRow++;
- }
- if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
- rc = shellDatabaseError(p->db);
- }
-
- /* Pretty-print the contents of array azResult[] to the output */
- if( rc==0 && nRow>0 ){
- int len, maxlen = 0;
- int i, j;
- int nPrintCol, nPrintRow;
- for(i=0; i<nRow; i++){
- len = strlen30(azResult[i]);
- if( len>maxlen ) maxlen = len;
- }
- nPrintCol = 80/(maxlen+2);
- if( nPrintCol<1 ) nPrintCol = 1;
- nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
- for(i=0; i<nPrintRow; i++){
- for(j=i; j<nRow; j+=nPrintRow){
- char *zSp = j<nPrintRow ? "" : " ";
- utf8_printf(p->out, "%s%-*s", zSp, maxlen,
- azResult[j] ? azResult[j]:"");
- }
- raw_printf(p->out, "\n");
- }
- }
-
- for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
- sqlite3_free(azResult);
- }else
-
- /* Begin redirecting output to the file "testcase-out.txt" */
- if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
- output_reset(p);
- p->out = output_file_open("testcase-out.txt");
- if( p->out==0 ){
- raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
- }
- if( nArg>=2 ){
- sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
- }else{
- sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");
- }
- }else
-
-#ifndef SQLITE_UNTESTABLE
- if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
- static const struct {
- const char *zCtrlName; /* Name of a test-control option */
- int ctrlCode; /* Integer code for that option */
- } aCtrl[] = {
- { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE },
- { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE },
- { "prng_reset", SQLITE_TESTCTRL_PRNG_RESET },
- { "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST },
- { "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL },
- { "benign_malloc_hooks", SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS },
- { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE },
- { "assert", SQLITE_TESTCTRL_ASSERT },
- { "always", SQLITE_TESTCTRL_ALWAYS },
- { "reserve", SQLITE_TESTCTRL_RESERVE },
- { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
- { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
- { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
- { "byteorder", SQLITE_TESTCTRL_BYTEORDER },
- { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
- { "imposter", SQLITE_TESTCTRL_IMPOSTER },
- };
- int testctrl = -1;
- int rc2 = 0;
- int i, n2;
- open_db(p, 0);
-
- /* convert testctrl text option to value. allow any unique prefix
- ** of the option name, or a numerical value. */
- n2 = strlen30(azArg[1]);
- for(i=0; i<ArraySize(aCtrl); i++){
- if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
- if( testctrl<0 ){
- testctrl = aCtrl[i].ctrlCode;
- }else{
- utf8_printf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
- testctrl = -1;
- break;
- }
- }
- }
- if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]);
- if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
- utf8_printf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
- }else{
- switch(testctrl){
-
- /* sqlite3_test_control(int, db, int) */
- case SQLITE_TESTCTRL_OPTIMIZATIONS:
- case SQLITE_TESTCTRL_RESERVE:
- if( nArg==3 ){
- int opt = (int)strtol(azArg[2], 0, 0);
- rc2 = sqlite3_test_control(testctrl, p->db, opt);
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- } else {
- utf8_printf(stderr,"Error: testctrl %s takes a single int option\n",
- azArg[1]);
- }
- break;
-
- /* sqlite3_test_control(int) */
- case SQLITE_TESTCTRL_PRNG_SAVE:
- case SQLITE_TESTCTRL_PRNG_RESTORE:
- case SQLITE_TESTCTRL_PRNG_RESET:
- case SQLITE_TESTCTRL_BYTEORDER:
- if( nArg==2 ){
- rc2 = sqlite3_test_control(testctrl);
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- } else {
- utf8_printf(stderr,"Error: testctrl %s takes no options\n",
- azArg[1]);
- }
- break;
-
- /* sqlite3_test_control(int, uint) */
- case SQLITE_TESTCTRL_PENDING_BYTE:
- if( nArg==3 ){
- unsigned int opt = (unsigned int)integerValue(azArg[2]);
- rc2 = sqlite3_test_control(testctrl, opt);
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- } else {
- utf8_printf(stderr,"Error: testctrl %s takes a single unsigned"
- " int option\n", azArg[1]);
- }
- break;
-
- /* sqlite3_test_control(int, int) */
- case SQLITE_TESTCTRL_ASSERT:
- case SQLITE_TESTCTRL_ALWAYS:
- case SQLITE_TESTCTRL_NEVER_CORRUPT:
- if( nArg==3 ){
- int opt = booleanValue(azArg[2]);
- rc2 = sqlite3_test_control(testctrl, opt);
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- } else {
- utf8_printf(stderr,"Error: testctrl %s takes a single int option\n",
- azArg[1]);
- }
- break;
-
- /* sqlite3_test_control(int, char *) */
-#ifdef SQLITE_N_KEYWORD
- case SQLITE_TESTCTRL_ISKEYWORD:
- if( nArg==3 ){
- const char *opt = azArg[2];
- rc2 = sqlite3_test_control(testctrl, opt);
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- } else {
- utf8_printf(stderr,
- "Error: testctrl %s takes a single char * option\n",
- azArg[1]);
- }
- break;
-#endif
-
- case SQLITE_TESTCTRL_IMPOSTER:
- if( nArg==5 ){
- rc2 = sqlite3_test_control(testctrl, p->db,
- azArg[2],
- integerValue(azArg[3]),
- integerValue(azArg[4]));
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- }else{
- raw_printf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
- }
- break;
-
- case SQLITE_TESTCTRL_BITVEC_TEST:
- case SQLITE_TESTCTRL_FAULT_INSTALL:
- case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
- case SQLITE_TESTCTRL_SCRATCHMALLOC:
- default:
- utf8_printf(stderr,
- "Error: CLI support for testctrl %s not implemented\n",
- azArg[1]);
- break;
- }
- }
- }else
-#endif /* !defined(SQLITE_UNTESTABLE) */
-
- if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){
- open_db(p, 0);
- sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
- }else
-
- if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){
- if( nArg==2 ){
- enableTimer = booleanValue(azArg[1]);
- if( enableTimer && !HAS_TIMER ){
- raw_printf(stderr, "Error: timer not available on this system.\n");
- enableTimer = 0;
- }
- }else{
- raw_printf(stderr, "Usage: .timer on|off\n");
- rc = 1;
- }
- }else
-
- if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
- open_db(p, 0);
- if( nArg!=2 ){
- raw_printf(stderr, "Usage: .trace FILE|off\n");
- rc = 1;
- goto meta_command_exit;
- }
- output_file_close(p->traceOut);
- p->traceOut = output_file_open(azArg[1]);
-#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
- if( p->traceOut==0 ){
- sqlite3_trace_v2(p->db, 0, 0, 0);
- }else{
- sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut);
- }
-#endif
- }else
-
-#if SQLITE_USER_AUTHENTICATION
- if( c=='u' && strncmp(azArg[0], "user", n)==0 ){
- if( nArg<2 ){
- raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n");
- rc = 1;
- goto meta_command_exit;
- }
- open_db(p, 0);
- if( strcmp(azArg[1],"login")==0 ){
- if( nArg!=4 ){
- raw_printf(stderr, "Usage: .user login USER PASSWORD\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
- (int)strlen(azArg[3]));
- if( rc ){
- utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
- rc = 1;
- }
- }else if( strcmp(azArg[1],"add")==0 ){
- if( nArg!=5 ){
- raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_add(p->db, azArg[2],
- azArg[3], (int)strlen(azArg[3]),
- booleanValue(azArg[4]));
- if( rc ){
- raw_printf(stderr, "User-Add failed: %d\n", rc);
- rc = 1;
- }
- }else if( strcmp(azArg[1],"edit")==0 ){
- if( nArg!=5 ){
- raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_change(p->db, azArg[2],
- azArg[3], (int)strlen(azArg[3]),
- booleanValue(azArg[4]));
- if( rc ){
- raw_printf(stderr, "User-Edit failed: %d\n", rc);
- rc = 1;
- }
- }else if( strcmp(azArg[1],"delete")==0 ){
- if( nArg!=3 ){
- raw_printf(stderr, "Usage: .user delete USER\n");
- rc = 1;
- goto meta_command_exit;
- }
- rc = sqlite3_user_delete(p->db, azArg[2]);
- if( rc ){
- raw_printf(stderr, "User-Delete failed: %d\n", rc);
- rc = 1;
- }
- }else{
- raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n");
- rc = 1;
- goto meta_command_exit;
- }
- }else
-#endif /* SQLITE_USER_AUTHENTICATION */
-
- if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
- utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
- sqlite3_libversion(), sqlite3_sourceid());
- }else
-
- if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){
- const char *zDbName = nArg==2 ? azArg[1] : "main";
- sqlite3_vfs *pVfs = 0;
- if( p->db ){
- sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
- if( pVfs ){
- utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName);
- raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
- raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
- raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
- }
- }
- }else
-
- if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){
- sqlite3_vfs *pVfs;
- sqlite3_vfs *pCurrent = 0;
- if( p->db ){
- sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent);
- }
- for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
- utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName,
- pVfs==pCurrent ? " <--- CURRENT" : "");
- raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion);
- raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile);
- raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname);
- if( pVfs->pNext ){
- raw_printf(p->out, "-----------------------------------\n");
- }
- }
- }else
-
- if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
- const char *zDbName = nArg==2 ? azArg[1] : "main";
- char *zVfsName = 0;
- if( p->db ){
- sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
- if( zVfsName ){
- utf8_printf(p->out, "%s\n", zVfsName);
- sqlite3_free(zVfsName);
- }
- }
- }else
-
-#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
- if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
- sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
- }else
-#endif
-
- if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
- int j;
- assert( nArg<=ArraySize(azArg) );
- for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
- p->colWidth[j-1] = (int)integerValue(azArg[j]);
- }
- }else
-
- {
- utf8_printf(stderr, "Error: unknown command or invalid arguments: "
- " \"%s\". Enter \".help\" for help\n", azArg[0]);
- rc = 1;
- }
-
-meta_command_exit:
- if( p->outCount ){
- p->outCount--;
- if( p->outCount==0 ) output_reset(p);
- }
- return rc;
-}
-
-/*
-** Return TRUE if a semicolon occurs anywhere in the first N characters
-** of string z[].
-*/
-static int line_contains_semicolon(const char *z, int N){
- int i;
- for(i=0; i<N; i++){ if( z[i]==';' ) return 1; }
- return 0;
-}
-
-/*
-** Test to see if a line consists entirely of whitespace.
-*/
-static int _all_whitespace(const char *z){
- for(; *z; z++){
- if( IsSpace(z[0]) ) continue;
- if( *z=='/' && z[1]=='*' ){
- z += 2;
- while( *z && (*z!='*' || z[1]!='/') ){ z++; }
- if( *z==0 ) return 0;
- z++;
- continue;
- }
- if( *z=='-' && z[1]=='-' ){
- z += 2;
- while( *z && *z!='\n' ){ z++; }
- if( *z==0 ) return 1;
- continue;
- }
- return 0;
- }
- return 1;
-}
-
-/*
-** Return TRUE if the line typed in is an SQL command terminator other
-** than a semi-colon. The SQL Server style "go" command is understood
-** as is the Oracle "/".
-*/
-static int line_is_command_terminator(const char *zLine){
- while( IsSpace(zLine[0]) ){ zLine++; };
- if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
- return 1; /* Oracle */
- }
- if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o'
- && _all_whitespace(&zLine[2]) ){
- return 1; /* SQL Server */
- }
- return 0;
-}
-
-/*
-** Return true if zSql is a complete SQL statement. Return false if it
-** ends in the middle of a string literal or C-style comment.
-*/
-static int line_is_complete(char *zSql, int nSql){
- int rc;
- if( zSql==0 ) return 1;
- zSql[nSql] = ';';
- zSql[nSql+1] = 0;
- rc = sqlite3_complete(zSql);
- zSql[nSql] = 0;
- return rc;
-}
-
-/*
-** Run a single line of SQL
-*/
-static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
- int rc;
- char *zErrMsg = 0;
-
- open_db(p, 0);
- if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql);
- BEGIN_TIMER;
- rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
- END_TIMER;
- if( rc || zErrMsg ){
- char zPrefix[100];
- if( in!=0 || !stdin_is_interactive ){
- sqlite3_snprintf(sizeof(zPrefix), zPrefix,
- "Error: near line %d:", startline);
- }else{
- sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
- }
- if( zErrMsg!=0 ){
- utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg);
- sqlite3_free(zErrMsg);
- zErrMsg = 0;
- }else{
- utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
- }
- return 1;
- }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
- raw_printf(p->out, "changes: %3d total_changes: %d\n",
- sqlite3_changes(p->db), sqlite3_total_changes(p->db));
- }
- return 0;
-}
-
-
-/*
-** Read input from *in and process it. If *in==0 then input
-** is interactive - the user is typing it it. Otherwise, input
-** is coming from a file or device. A prompt is issued and history
-** is saved only if input is interactive. An interrupt signal will
-** cause this routine to exit immediately, unless input is interactive.
-**
-** Return the number of errors.
-*/
-static int process_input(ShellState *p, FILE *in){
- char *zLine = 0; /* A single input line */
- char *zSql = 0; /* Accumulated SQL text */
- int nLine; /* Length of current line */
- int nSql = 0; /* Bytes of zSql[] used */
- int nAlloc = 0; /* Allocated zSql[] space */
- int nSqlPrior = 0; /* Bytes of zSql[] used by prior line */
- int rc; /* Error code */
- int errCnt = 0; /* Number of errors seen */
- int lineno = 0; /* Current line number */
- int startline = 0; /* Line number for start of current input */
-
- while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
- fflush(p->out);
- zLine = one_input_line(in, zLine, nSql>0);
- if( zLine==0 ){
- /* End of input */
- if( in==0 && stdin_is_interactive ) printf("\n");
- break;
- }
- if( seenInterrupt ){
- if( in!=0 ) break;
- seenInterrupt = 0;
- }
- lineno++;
- if( nSql==0 && _all_whitespace(zLine) ){
- if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
- continue;
- }
- if( zLine && zLine[0]=='.' && nSql==0 ){
- if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
- rc = do_meta_command(zLine, p);
- if( rc==2 ){ /* exit requested */
- break;
- }else if( rc ){
- errCnt++;
- }
- continue;
- }
- if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){
- memcpy(zLine,";",2);
- }
- nLine = strlen30(zLine);
- if( nSql+nLine+2>=nAlloc ){
- nAlloc = nSql+nLine+100;
- zSql = realloc(zSql, nAlloc);
- if( zSql==0 ){
- raw_printf(stderr, "Error: out of memory\n");
- exit(1);
- }
- }
- nSqlPrior = nSql;
- if( nSql==0 ){
- int i;
- for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
- assert( nAlloc>0 && zSql!=0 );
- memcpy(zSql, zLine+i, nLine+1-i);
- startline = lineno;
- nSql = nLine-i;
- }else{
- zSql[nSql++] = '\n';
- memcpy(zSql+nSql, zLine, nLine+1);
- nSql += nLine;
- }
- if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
- && sqlite3_complete(zSql) ){
- errCnt += runOneSqlLine(p, zSql, in, startline);
- nSql = 0;
- if( p->outCount ){
- output_reset(p);
- p->outCount = 0;
- }
- }else if( nSql && _all_whitespace(zSql) ){
- if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
- nSql = 0;
- }
- }
- if( nSql && !_all_whitespace(zSql) ){
- runOneSqlLine(p, zSql, in, startline);
- }
- free(zSql);
- free(zLine);
- return errCnt>0;
-}
-
-/*
-** Return a pathname which is the user's home directory. A
-** 0 return indicates an error of some kind.
-*/
-static char *find_home_dir(int clearFlag){
- static char *home_dir = NULL;
- if( clearFlag ){
- free(home_dir);
- home_dir = 0;
- return 0;
- }
- if( home_dir ) return home_dir;
-
-#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
- && !defined(__RTP__) && !defined(_WRS_KERNEL)
- {
- struct passwd *pwent;
- uid_t uid = getuid();
- if( (pwent=getpwuid(uid)) != NULL) {
- home_dir = pwent->pw_dir;
- }
- }
-#endif
-
-#if defined(_WIN32_WCE)
- /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
- */
- home_dir = "/";
-#else
-
-#if defined(_WIN32) || defined(WIN32)
- if (!home_dir) {
- home_dir = getenv("USERPROFILE");
- }
-#endif
-
- if (!home_dir) {
- home_dir = getenv("HOME");
- }
-
-#if defined(_WIN32) || defined(WIN32)
- if (!home_dir) {
- char *zDrive, *zPath;
- int n;
- zDrive = getenv("HOMEDRIVE");
- zPath = getenv("HOMEPATH");
- if( zDrive && zPath ){
- n = strlen30(zDrive) + strlen30(zPath) + 1;
- home_dir = malloc( n );
- if( home_dir==0 ) return 0;
- sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
- return home_dir;
- }
- home_dir = "c:\\";
- }
-#endif
-
-#endif /* !_WIN32_WCE */
-
- if( home_dir ){
- int n = strlen30(home_dir) + 1;
- char *z = malloc( n );
- if( z ) memcpy(z, home_dir, n);
- home_dir = z;
- }
-
- return home_dir;
-}
-
-/*
-** Read input from the file given by sqliterc_override. Or if that
-** parameter is NULL, take input from ~/.sqliterc
-**
-** Returns the number of errors.
-*/
-static void process_sqliterc(
- ShellState *p, /* Configuration data */
- const char *sqliterc_override /* Name of config file. NULL to use default */
-){
- char *home_dir = NULL;
- const char *sqliterc = sqliterc_override;
- char *zBuf = 0;
- FILE *in = NULL;
-
- if (sqliterc == NULL) {
- home_dir = find_home_dir(0);
- if( home_dir==0 ){
- raw_printf(stderr, "-- warning: cannot find home directory;"
- " cannot read ~/.sqliterc\n");
- return;
- }
- sqlite3_initialize();
- zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
- sqliterc = zBuf;
- }
- in = fopen(sqliterc,"rb");
- if( in ){
- if( stdin_is_interactive ){
- utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
- }
- process_input(p,in);
- fclose(in);
- }
- sqlite3_free(zBuf);
-}
-
-/*
-** Show available command line options
-*/
-static const char zOptions[] =
- " -ascii set output mode to 'ascii'\n"
- " -bail stop after hitting an error\n"
- " -batch force batch I/O\n"
- " -column set output mode to 'column'\n"
- " -cmd COMMAND run \"COMMAND\" before reading stdin\n"
- " -csv set output mode to 'csv'\n"
- " -echo print commands before execution\n"
- " -init FILENAME read/process named file\n"
- " -[no]header turn headers on or off\n"
-#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
- " -heap SIZE Size of heap for memsys3 or memsys5\n"
-#endif
- " -help show this message\n"
- " -html set output mode to HTML\n"
- " -interactive force interactive I/O\n"
- " -line set output mode to 'line'\n"
- " -list set output mode to 'list'\n"
- " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
- " -mmap N default mmap size set to N\n"
-#ifdef SQLITE_ENABLE_MULTIPLEX
- " -multiplex enable the multiplexor VFS\n"
-#endif
- " -newline SEP set output row separator. Default: '\\n'\n"
- " -nullvalue TEXT set text string for NULL values. Default ''\n"
- " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
- " -quote set output mode to 'quote'\n"
- " -scratch SIZE N use N slots of SZ bytes each for scratch memory\n"
- " -separator SEP set output column separator. Default: '|'\n"
- " -stats print memory stats before each finalize\n"
- " -version show SQLite version\n"
- " -vfs NAME use NAME as the default VFS\n"
-#ifdef SQLITE_ENABLE_VFSTRACE
- " -vfstrace enable tracing of all VFS calls\n"
-#endif
-;
-static void usage(int showDetail){
- utf8_printf(stderr,
- "Usage: %s [OPTIONS] FILENAME [SQL]\n"
- "FILENAME is the name of an SQLite database. A new database is created\n"
- "if the file does not previously exist.\n", Argv0);
- if( showDetail ){
- utf8_printf(stderr, "OPTIONS include:\n%s", zOptions);
- }else{
- raw_printf(stderr, "Use the -help option for additional information\n");
- }
- exit(1);
-}
-
-/*
-** Initialize the state information in data
-*/
-static void main_init(ShellState *data) {
- memset(data, 0, sizeof(*data));
- data->normalMode = data->cMode = data->mode = MODE_List;
- data->autoExplain = 1;
- memcpy(data->colSeparator,SEP_Column, 2);
- memcpy(data->rowSeparator,SEP_Row, 2);
- data->showHeader = 0;
- data->shellFlgs = SHFLG_Lookaside;
- sqlite3_config(SQLITE_CONFIG_URI, 1);
- sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
- sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
- sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
- sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
-}
-
-/*
-** Output text to the console in a font that attracts extra attention.
-*/
-#ifdef _WIN32
-static void printBold(const char *zText){
- HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
- CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
- GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
- SetConsoleTextAttribute(out,
- FOREGROUND_RED|FOREGROUND_INTENSITY
- );
- printf("%s", zText);
- SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
-}
-#else
-static void printBold(const char *zText){
- printf("\033[1m%s\033[0m", zText);
-}
-#endif
-
-/*
-** Get the argument to an --option. Throw an error and die if no argument
-** is available.
-*/
-static char *cmdline_option_value(int argc, char **argv, int i){
- if( i==argc ){
- utf8_printf(stderr, "%s: Error: missing argument to %s\n",
- argv[0], argv[argc-1]);
- exit(1);
- }
- return argv[i];
-}
-
-#ifndef SQLITE_SHELL_IS_UTF8
-# if (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)
-# define SQLITE_SHELL_IS_UTF8 (0)
-# else
-# define SQLITE_SHELL_IS_UTF8 (1)
-# endif
-#endif
-
-#if SQLITE_SHELL_IS_UTF8
-int SQLITE_CDECL main(int argc, char **argv){
-#else
-int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
- char **argv;
-#endif
- char *zErrMsg = 0;
- ShellState data;
- const char *zInitFile = 0;
- int i;
- int rc = 0;
- int warnInmemoryDb = 0;
- int readStdin = 1;
- int nCmd = 0;
- char **azCmd = 0;
-
- setBinaryMode(stdin, 0);
- setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
- stdin_is_interactive = isatty(0);
- stdout_is_console = isatty(1);
-
-#if USE_SYSTEM_SQLITE+0!=1
- if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
- utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
- sqlite3_sourceid(), SQLITE_SOURCE_ID);
- exit(1);
- }
-#endif
- main_init(&data);
-#if !SQLITE_SHELL_IS_UTF8
- sqlite3_initialize();
- argv = sqlite3_malloc64(sizeof(argv[0])*argc);
- if( argv==0 ){
- raw_printf(stderr, "out of memory\n");
- exit(1);
- }
- for(i=0; i<argc; i++){
- argv[i] = sqlite3_win32_unicode_to_utf8(wargv[i]);
- if( argv[i]==0 ){
- raw_printf(stderr, "out of memory\n");
- exit(1);
- }
- }
-#endif
- assert( argc>=1 && argv && argv[0] );
- Argv0 = argv[0];
-
- /* Make sure we have a valid signal handler early, before anything
- ** else is done.
- */
-#ifdef SIGINT
- signal(SIGINT, interrupt_handler);
-#endif
-
-#ifdef SQLITE_SHELL_DBNAME_PROC
- {
- /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
- ** of a C-function that will provide the name of the database file. Use
- ** this compile-time option to embed this shell program in larger
- ** applications. */
- extern void SQLITE_SHELL_DBNAME_PROC(const char**);
- SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename);
- warnInmemoryDb = 0;
- }
-#endif
-
- /* Begin evanm patch. */
-#if !defined(__APPLE__)
- extern int sqlite_shell_init_icu();
- if( !sqlite_shell_init_icu() ){
- fprintf(stderr, "%s: warning: couldn't find icudt38.dll; "
- "queries against ICU FTS tables will fail.\n", argv[0]);
- }
-#endif /* !defined(__APPLE__) */
- /* End evanm patch. */
-
- /* Do an initial pass through the command-line argument to locate
- ** the name of the database file, the name of the initialization file,
- ** the size of the alternative malloc heap,
- ** and the first command to execute.
- */
- for(i=1; i<argc; i++){
- char *z;
- z = argv[i];
- if( z[0]!='-' ){
- if( data.zDbFilename==0 ){
- data.zDbFilename = z;
- }else{
- /* Excesss arguments are interpreted as SQL (or dot-commands) and
- ** mean that nothing is read from stdin */
- readStdin = 0;
- nCmd++;
- azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
- if( azCmd==0 ){
- raw_printf(stderr, "out of memory\n");
- exit(1);
- }
- azCmd[nCmd-1] = z;
- }
- }
- if( z[1]=='-' ) z++;
- if( strcmp(z,"-separator")==0
- || strcmp(z,"-nullvalue")==0
- || strcmp(z,"-newline")==0
- || strcmp(z,"-cmd")==0
- ){
- (void)cmdline_option_value(argc, argv, ++i);
- }else if( strcmp(z,"-init")==0 ){
- zInitFile = cmdline_option_value(argc, argv, ++i);
- }else if( strcmp(z,"-batch")==0 ){
- /* Need to check for batch mode here to so we can avoid printing
- ** informational messages (like from process_sqliterc) before
- ** we do the actual processing of arguments later in a second pass.
- */
- stdin_is_interactive = 0;
- }else if( strcmp(z,"-heap")==0 ){
-#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
- const char *zSize;
- sqlite3_int64 szHeap;
-
- zSize = cmdline_option_value(argc, argv, ++i);
- szHeap = integerValue(zSize);
- if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
- sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
-#else
- (void)cmdline_option_value(argc, argv, ++i);
-#endif
- }else if( strcmp(z,"-scratch")==0 ){
- int n, sz;
- sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
- if( sz>400000 ) sz = 400000;
- if( sz<2500 ) sz = 2500;
- n = (int)integerValue(cmdline_option_value(argc,argv,++i));
- if( n>10 ) n = 10;
- if( n<1 ) n = 1;
- sqlite3_config(SQLITE_CONFIG_SCRATCH, malloc(n*sz+1), sz, n);
- data.shellFlgs |= SHFLG_Scratch;
- }else if( strcmp(z,"-pagecache")==0 ){
- int n, sz;
- sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
- if( sz>70000 ) sz = 70000;
- if( sz<0 ) sz = 0;
- n = (int)integerValue(cmdline_option_value(argc,argv,++i));
- sqlite3_config(SQLITE_CONFIG_PAGECACHE,
- (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
- data.shellFlgs |= SHFLG_Pagecache;
- }else if( strcmp(z,"-lookaside")==0 ){
- int n, sz;
- sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
- if( sz<0 ) sz = 0;
- n = (int)integerValue(cmdline_option_value(argc,argv,++i));
- if( n<0 ) n = 0;
- sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n);
- if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;
-#ifdef SQLITE_ENABLE_VFSTRACE
- }else if( strcmp(z,"-vfstrace")==0 ){
- extern int vfstrace_register(
- const char *zTraceName,
- const char *zOldVfsName,
- int (*xOut)(const char*,void*),
- void *pOutArg,
- int makeDefault
- );
- vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
-#endif
-#ifdef SQLITE_ENABLE_MULTIPLEX
- }else if( strcmp(z,"-multiplex")==0 ){
- extern int sqlite3_multiple_initialize(const char*,int);
- sqlite3_multiplex_initialize(0, 1);
-#endif
- }else if( strcmp(z,"-mmap")==0 ){
- sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
- sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
- }else if( strcmp(z,"-vfs")==0 ){
- sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i));
- if( pVfs ){
- sqlite3_vfs_register(pVfs, 1);
- }else{
- utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]);
- exit(1);
- }
- }
- }
- if( data.zDbFilename==0 ){
-#ifndef SQLITE_OMIT_MEMORYDB
- data.zDbFilename = ":memory:";
- warnInmemoryDb = argc==1;
-#else
- utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0);
- return 1;
-#endif
- }
- data.out = stdout;
-
- /* Go ahead and open the database file if it already exists. If the
- ** file does not exist, delay opening it. This prevents empty database
- ** files from being created if a user mistypes the database name argument
- ** to the sqlite command-line tool.
- */
- if( access(data.zDbFilename, 0)==0 ){
- open_db(&data, 0);
- }
-
- /* Process the initialization file if there is one. If no -init option
- ** is given on the command line, look for a file named ~/.sqliterc and
- ** try to process it.
- */
- process_sqliterc(&data,zInitFile);
-
- /* Make a second pass through the command-line argument and set
- ** options. This second pass is delayed until after the initialization
- ** file is processed so that the command-line arguments will override
- ** settings in the initialization file.
- */
- for(i=1; i<argc; i++){
- char *z = argv[i];
- if( z[0]!='-' ) continue;
- if( z[1]=='-' ){ z++; }
- if( strcmp(z,"-init")==0 ){
- i++;
- }else if( strcmp(z,"-html")==0 ){
- data.mode = MODE_Html;
- }else if( strcmp(z,"-list")==0 ){
- data.mode = MODE_List;
- }else if( strcmp(z,"-quote")==0 ){
- data.mode = MODE_Quote;
- }else if( strcmp(z,"-line")==0 ){
- data.mode = MODE_Line;
- }else if( strcmp(z,"-column")==0 ){
- data.mode = MODE_Column;
- }else if( strcmp(z,"-csv")==0 ){
- data.mode = MODE_Csv;
- memcpy(data.colSeparator,",",2);
- }else if( strcmp(z,"-ascii")==0 ){
- data.mode = MODE_Ascii;
- sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
- SEP_Unit);
- sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
- SEP_Record);
- }else if( strcmp(z,"-separator")==0 ){
- sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
- "%s",cmdline_option_value(argc,argv,++i));
- }else if( strcmp(z,"-newline")==0 ){
- sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
- "%s",cmdline_option_value(argc,argv,++i));
- }else if( strcmp(z,"-nullvalue")==0 ){
- sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
- "%s",cmdline_option_value(argc,argv,++i));
- }else if( strcmp(z,"-header")==0 ){
- data.showHeader = 1;
- }else if( strcmp(z,"-noheader")==0 ){
- data.showHeader = 0;
- }else if( strcmp(z,"-echo")==0 ){
- ShellSetFlag(&data, SHFLG_Echo);
- }else if( strcmp(z,"-eqp")==0 ){
- data.autoEQP = 1;
- }else if( strcmp(z,"-eqpfull")==0 ){
- data.autoEQP = 2;
- }else if( strcmp(z,"-stats")==0 ){
- data.statsOn = 1;
- }else if( strcmp(z,"-scanstats")==0 ){
- data.scanstatsOn = 1;
- }else if( strcmp(z,"-backslash")==0 ){
- /* Undocumented command-line option: -backslash
- ** Causes C-style backslash escapes to be evaluated in SQL statements
- ** prior to sending the SQL into SQLite. Useful for injecting
- ** crazy bytes in the middle of SQL statements for testing and debugging.
- */
- ShellSetFlag(&data, SHFLG_Backslash);
- }else if( strcmp(z,"-bail")==0 ){
- bail_on_error = 1;
- }else if( strcmp(z,"-version")==0 ){
- printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
- return 0;
- }else if( strcmp(z,"-interactive")==0 ){
- stdin_is_interactive = 1;
- }else if( strcmp(z,"-batch")==0 ){
- stdin_is_interactive = 0;
- }else if( strcmp(z,"-heap")==0 ){
- i++;
- }else if( strcmp(z,"-scratch")==0 ){
- i+=2;
- }else if( strcmp(z,"-pagecache")==0 ){
- i+=2;
- }else if( strcmp(z,"-lookaside")==0 ){
- i+=2;
- }else if( strcmp(z,"-mmap")==0 ){
- i++;
- }else if( strcmp(z,"-vfs")==0 ){
- i++;
-#ifdef SQLITE_ENABLE_VFSTRACE
- }else if( strcmp(z,"-vfstrace")==0 ){
- i++;
-#endif
-#ifdef SQLITE_ENABLE_MULTIPLEX
- }else if( strcmp(z,"-multiplex")==0 ){
- i++;
-#endif
- }else if( strcmp(z,"-help")==0 ){
- usage(1);
- }else if( strcmp(z,"-cmd")==0 ){
- /* Run commands that follow -cmd first and separately from commands
- ** that simply appear on the command-line. This seems goofy. It would
- ** be better if all commands ran in the order that they appear. But
- ** we retain the goofy behavior for historical compatibility. */
- if( i==argc-1 ) break;
- z = cmdline_option_value(argc,argv,++i);
- if( z[0]=='.' ){
- rc = do_meta_command(z, &data);
- if( rc && bail_on_error ) return rc==2 ? 0 : rc;
- }else{
- open_db(&data, 0);
- rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
- if( zErrMsg!=0 ){
- utf8_printf(stderr,"Error: %s\n", zErrMsg);
- if( bail_on_error ) return rc!=0 ? rc : 1;
- }else if( rc!=0 ){
- utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z);
- if( bail_on_error ) return rc;
- }
- }
- }else{
- utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
- raw_printf(stderr,"Use -help for a list of options.\n");
- return 1;
- }
- data.cMode = data.mode;
- }
-
- if( !readStdin ){
- /* Run all arguments that do not begin with '-' as if they were separate
- ** command-line inputs, except for the argToSkip argument which contains
- ** the database filename.
- */
- for(i=0; i<nCmd; i++){
- if( azCmd[i][0]=='.' ){
- rc = do_meta_command(azCmd[i], &data);
- if( rc ) return rc==2 ? 0 : rc;
- }else{
- open_db(&data, 0);
- rc = shell_exec(data.db, azCmd[i], shell_callback, &data, &zErrMsg);
- if( zErrMsg!=0 ){
- utf8_printf(stderr,"Error: %s\n", zErrMsg);
- return rc!=0 ? rc : 1;
- }else if( rc!=0 ){
- utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
- return rc;
- }
- }
- }
- free(azCmd);
- }else{
- /* Run commands received from standard input
- */
- if( stdin_is_interactive ){
- char *zHome;
- char *zHistory = 0;
- int nHistory;
- printf(
- "SQLite version %s %.19s\n" /*extra-version-info*/
- "Enter \".help\" for usage hints.\n",
- sqlite3_libversion(), sqlite3_sourceid()
- );
- if( warnInmemoryDb ){
- printf("Connected to a ");
- printBold("transient in-memory database");
- printf(".\nUse \".open FILENAME\" to reopen on a "
- "persistent database.\n");
- }
- zHome = find_home_dir(0);
- if( zHome ){
- nHistory = strlen30(zHome) + 20;
- if( (zHistory = malloc(nHistory))!=0 ){
- sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
- }
- }
- if( zHistory ){ shell_read_history(zHistory); }
-#if HAVE_READLINE || HAVE_EDITLINE
- rl_attempted_completion_function = readline_completion;
-#elif HAVE_LINENOISE
- linenoiseSetCompletionCallback(linenoise_completion);
-#endif
- rc = process_input(&data, 0);
- if( zHistory ){
- shell_stifle_history(2000);
- shell_write_history(zHistory);
- free(zHistory);
- }
- }else{
- rc = process_input(&data, stdin);
- }
- }
- set_table_name(&data, 0);
- if( data.db ){
- session_close_all(&data);
- sqlite3_close(data.db);
- }
- sqlite3_free(data.zFreeOnClose);
- find_home_dir(1);
-#if !SQLITE_SHELL_IS_UTF8
- for(i=0; i<argc; i++) sqlite3_free(argv[i]);
- sqlite3_free(argv);
-#endif
- return rc;
-}
-
diff --git a/third_party/sqlite/src/src/shell.c.in b/third_party/sqlite/src/src/shell.c.in
index 4dac4a6..a500a19 100644
--- a/third_party/sqlite/src/src/shell.c.in
+++ b/third_party/sqlite/src/src/shell.c.in
@@ -871,14 +871,13 @@ struct ShellState {
/*
** These are the allowed shellFlgs values
*/
-#define SHFLG_Scratch 0x00000001 /* The --scratch option is used */
-#define SHFLG_Pagecache 0x00000002 /* The --pagecache option is used */
-#define SHFLG_Lookaside 0x00000004 /* Lookaside memory is used */
-#define SHFLG_Backslash 0x00000008 /* The --backslash option is used */
-#define SHFLG_PreserveRowid 0x00000010 /* .dump preserves rowid values */
-#define SHFLG_Newlines 0x00000020 /* .dump --newline flag */
-#define SHFLG_CountChanges 0x00000040 /* .changes setting */
-#define SHFLG_Echo 0x00000080 /* .echo or --echo setting */
+#define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
+#define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
+#define SHFLG_Backslash 0x00000004 /* The --backslash option is used */
+#define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */
+#define SHFLG_Newlines 0x00000010 /* .dump --newline flag */
+#define SHFLG_CountChanges 0x00000020 /* .changes setting */
+#define SHFLG_Echo 0x00000040 /* .echo or --echo setting */
/*
** Macros for testing and setting shellFlgs
@@ -1299,6 +1298,7 @@ static int shell_callback(
int i;
ShellState *p = (ShellState*)pArg;
+ if( azArg==0 ) return 0;
switch( p->cMode ){
case MODE_Line: {
int w = 5;
@@ -1413,6 +1413,7 @@ static int shell_callback(
for(i=0; IsSpace(z[i]); i++){}
for(; (c = z[i])!=0; i++){
if( IsSpace(c) ){
+ if( z[j-1]=='\r' ) z[j-1] = '\n';
if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
}else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
j--;
@@ -1649,6 +1650,7 @@ static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){
ShellText *p = (ShellText*)pArg;
int i;
UNUSED_PARAMETER(az);
+ if( azArg==0 ) return 0;
if( p->n ) appendText(p, "|", 0);
for(i=0; i<nArg; i++){
if( i ) appendText(p, ",", 0);
@@ -1713,7 +1715,7 @@ static void createSelftestTable(ShellState *p){
*/
static void set_table_name(ShellState *p, const char *zName){
int i, n;
- int cQuote;
+ char cQuote;
char *z;
if( p->zDestTable ){
@@ -1895,18 +1897,10 @@ static int display_stats(
}
displayStatLine(pArg, "Number of Pcache Overflow Bytes:",
"%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
- if( pArg->shellFlgs & SHFLG_Scratch ){
- displayStatLine(pArg, "Number of Scratch Allocations Used:",
- "%lld (max %lld)", SQLITE_STATUS_SCRATCH_USED, bReset);
- }
- displayStatLine(pArg, "Number of Scratch Overflow Bytes:",
- "%lld (max %lld) bytes", SQLITE_STATUS_SCRATCH_OVERFLOW, bReset);
displayStatLine(pArg, "Largest Allocation:",
"%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
displayStatLine(pArg, "Largest Pcache Allocation:",
"%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
- displayStatLine(pArg, "Largest Scratch Allocation:",
- "%lld bytes", SQLITE_STATUS_SCRATCH_SIZE, bReset);
#ifdef YYTRACKMAXSTACKDEPTH
displayStatLine(pArg, "Deepest Parser Stack:",
"%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
@@ -2447,6 +2441,7 @@ static char **tableColumnList(ShellState *p, const char *zTab){
}
}
sqlite3_finalize(pStmt);
+ if( azCol==0 ) return 0;
azCol[0] = 0;
azCol[nCol+1] = 0;
@@ -2530,7 +2525,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
ShellState *p = (ShellState *)pArg;
UNUSED_PARAMETER(azNotUsed);
- if( nArg!=3 ) return 1;
+ if( nArg!=3 || azArg==0 ) return 0;
zTable = azArg[0];
zType = azArg[1];
zSql = azArg[2];
@@ -3616,20 +3611,24 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
{ "schema size:",
"SELECT total(length(sql)) FROM %s" },
};
- sqlite3_file *pFile = 0;
int i;
char *zSchemaTab;
char *zDb = nArg>=2 ? azArg[1] : "main";
+ sqlite3_stmt *pStmt = 0;
unsigned char aHdr[100];
open_db(p, 0);
if( p->db==0 ) return 1;
- sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
- if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
- return 1;
- }
- i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
- if( i!=SQLITE_OK ){
+ sqlite3_prepare_v2(p->db,"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
+ -1, &pStmt, 0);
+ sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
+ if( sqlite3_step(pStmt)==SQLITE_ROW
+ && sqlite3_column_bytes(pStmt,0)>100
+ ){
+ memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100);
+ sqlite3_finalize(pStmt);
+ }else{
raw_printf(stderr, "unable to read database header\n");
+ sqlite3_finalize(pStmt);
return 1;
}
i = get2byteInt(aHdr+16);
@@ -4249,7 +4248,7 @@ static int do_meta_command(char *zLine, ShellState *p){
utf8_printf(stderr,
"testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
p->zTestcase, azArg[1], zRes);
- rc = 2;
+ rc = 1;
}else{
utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
p->nCheck++;
@@ -5927,7 +5926,6 @@ static int do_meta_command(char *zLine, ShellState *p){
{ "reserve", SQLITE_TESTCTRL_RESERVE },
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
- { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
{ "imposter", SQLITE_TESTCTRL_IMPOSTER },
@@ -6040,7 +6038,6 @@ static int do_meta_command(char *zLine, ShellState *p){
case SQLITE_TESTCTRL_BITVEC_TEST:
case SQLITE_TESTCTRL_FAULT_INSTALL:
case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
- case SQLITE_TESTCTRL_SCRATCHMALLOC:
default:
utf8_printf(stderr,
"Error: CLI support for testctrl %s not implemented\n",
@@ -6560,7 +6557,6 @@ static const char zOptions[] =
" -nullvalue TEXT set text string for NULL values. Default ''\n"
" -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
" -quote set output mode to 'quote'\n"
- " -scratch SIZE N use N slots of SZ bytes each for scratch memory\n"
" -separator SEP set output column separator. Default: '|'\n"
" -stats print memory stats before each finalize\n"
" -version show SQLite version\n"
@@ -6663,7 +6659,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
stdout_is_console = isatty(1);
#if USE_SYSTEM_SQLITE+0!=1
- if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
+ if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
sqlite3_sourceid(), SQLITE_SOURCE_ID);
exit(1);
@@ -6707,6 +6703,16 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}
#endif
+ /* Begin evanm patch. */
+#if !defined(__APPLE__)
+ extern int sqlite_shell_init_icu();
+ if( !sqlite_shell_init_icu() ){
+ fprintf(stderr, "%s: warning: couldn't find icudt38.dll; "
+ "queries against ICU FTS tables will fail.\n", argv[0]);
+ }
+#endif /* !defined(__APPLE__) */
+ /* End evanm patch. */
+
/* Do an initial pass through the command-line argument to locate
** the name of the database file, the name of the initialization file,
** the size of the alternative malloc heap,
@@ -6758,16 +6764,6 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#else
(void)cmdline_option_value(argc, argv, ++i);
#endif
- }else if( strcmp(z,"-scratch")==0 ){
- int n, sz;
- sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
- if( sz>400000 ) sz = 400000;
- if( sz<2500 ) sz = 2500;
- n = (int)integerValue(cmdline_option_value(argc,argv,++i));
- if( n>10 ) n = 10;
- if( n<1 ) n = 1;
- sqlite3_config(SQLITE_CONFIG_SCRATCH, malloc(n*sz+1), sz, n);
- data.shellFlgs |= SHFLG_Scratch;
}else if( strcmp(z,"-pagecache")==0 ){
int n, sz;
sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
@@ -6911,8 +6907,6 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
stdin_is_interactive = 0;
}else if( strcmp(z,"-heap")==0 ){
i++;
- }else if( strcmp(z,"-scratch")==0 ){
- i+=2;
}else if( strcmp(z,"-pagecache")==0 ){
i+=2;
}else if( strcmp(z,"-lookaside")==0 ){
diff --git a/third_party/sqlite/src/src/sqlite.h.in b/third_party/sqlite/src/src/sqlite.h.in
index 2503d76..83b14ae7 100644
--- a/third_party/sqlite/src/src/sqlite.h.in
+++ b/third_party/sqlite/src/src/sqlite.h.in
@@ -115,7 +115,9 @@ extern "C" {
** a string which identifies a particular check-in of SQLite
** within its configuration management system. ^The SQLITE_SOURCE_ID
** string contains the date and time of the check-in (UTC) and a SHA1
-** or SHA3-256 hash of the entire source tree.
+** or SHA3-256 hash of the entire source tree. If the source code has
+** been edited in any way since it was last checked in, then the last
+** four hexadecimal digits of the hash may be modified.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
@@ -139,7 +141,7 @@ extern "C" {
**
** <blockquote><pre>
** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
-** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
+** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
** </pre></blockquote>)^
**
@@ -149,9 +151,11 @@ 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
+** [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.
+** [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].)^
**
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
@@ -432,7 +436,7 @@ int sqlite3_exec(
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
-#define SQLITE_EMPTY 16 /* Not used */
+#define SQLITE_EMPTY 16 /* Internal use only */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
@@ -494,6 +498,9 @@ int sqlite3_exec(
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
+#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_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
@@ -580,6 +587,11 @@ int sqlite3_exec(
** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on
** read-only media and cannot be changed even by processes with
** elevated privileges.
+**
+** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
+** filesystem supports doing multiple write operations atomically when those
+** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
+** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -595,6 +607,7 @@ int sqlite3_exec(
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
+#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
/*
** CAPI3REF: File Locking Levels
@@ -729,6 +742,7 @@ struct sqlite3_file {
** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
** <li> [SQLITE_IOCAP_IMMUTABLE]
+** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
** </ul>
**
** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -1012,6 +1026,40 @@ struct sqlite3_io_methods {
** 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.
+**
+** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
+** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
+** the file descriptor is placed in "batch write mode", which
+** means all subsequent write operations will be deferred and done
+** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems
+** that do not support batch atomic writes will return SQLITE_NOTFOUND.
+** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
+** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
+** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
+** no VFS interface calls on the same [sqlite3_file] file descriptor
+** except for calls to the xWrite method and the xFileControl method
+** with [SQLITE_FCNTL_SIZE_HINT].
+**
+** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
+** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
+** 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.
+** ^Regardless of whether or not it is successful, this file control takes
+** the file descriptor out of batch write mode so that all subsequent
+** write operations are independent.
+** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
+** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
+**
+** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
+** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
+** 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.
+** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
+** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1043,6 +1091,9 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_JOURNAL_POINTER 28
#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
#define SQLITE_FCNTL_PDB 30
+#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31
+#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32
+#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1613,6 +1664,16 @@ struct sqlite3_mem_methods {
** routines with a wrapper that simulations memory allocation failure or
** tracks memory usage, for example. </dd>
**
+** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt>
+** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of
+** type int, interpreted as a boolean, which if true provides a hint to
+** SQLite that it should avoid large memory allocations if possible.
+** SQLite will run faster if it is free to make large memory allocations,
+** but some application might prefer to run slower in exchange for
+** guarantees about memory fragmentation that are possible if large
+** allocations are avoided. This hint is normally off.
+** </dd>
+**
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
** interpreted as a boolean, which enables or disables the collection of
@@ -1630,25 +1691,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
-** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
-** that SQLite can use for scratch memory. ^(There are three arguments
-** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte
-** aligned memory buffer from which the scratch allocations will be
-** drawn, the size of each scratch allocation (sz),
-** and the maximum number of scratch allocations (N).)^
-** The first argument must be a pointer to an 8-byte aligned buffer
-** of at least sz*N bytes of memory.
-** ^SQLite will not use more than one scratch buffers per thread.
-** ^SQLite will never request a scratch buffer that is more than 6
-** times the database page size.
-** ^If SQLite needs needs additional
-** scratch memory beyond what is provided by this configuration option, then
-** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
-** ^When the application provides any amount of scratch memory using
-** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
-** [sqlite3_malloc|heap allocations].
-** This can help [Robson proof|prevent memory allocation failures] due to heap
-** fragmentation in low-memory embedded systems.
+** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
@@ -1684,8 +1727,7 @@ struct sqlite3_mem_methods {
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
** <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_SCRATCH] and
-** [SQLITE_CONFIG_PAGECACHE].
+** beyond those provided for by [SQLITE_CONFIG_PAGECACHE].
** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
** [SQLITE_ERROR] if invoked otherwise.
@@ -1878,7 +1920,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
@@ -1899,6 +1941,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */
+#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -3099,10 +3142,10 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** ^If [URI filename] interpretation is enabled, and the filename argument
** begins with "file:", then the filename is interpreted as a URI. ^URI
** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
-** set in the fourth argument to sqlite3_open_v2(), or if it has
+** set in the third argument to sqlite3_open_v2(), or if it has
** been enabled globally using the [SQLITE_CONFIG_URI] option with the
** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
-** As of SQLite version 3.7.7, URI filename interpretation is turned off
+** URI filename interpretation is turned off
** by default, but future releases of SQLite might enable URI filename
** interpretation by default. See "[URI filenames]" for additional
** information.
@@ -3776,8 +3819,9 @@ int sqlite3_stmt_busy(sqlite3_stmt*);
** implementation of [application-defined SQL functions] are protected.
** ^The sqlite3_value object returned by
** [sqlite3_column_value()] is unprotected.
-** Unprotected sqlite3_value objects may only be used with
-** [sqlite3_result_value()] and [sqlite3_bind_value()].
+** Unprotected sqlite3_value objects may only be used as arguments
+** to [sqlite3_result_value()], [sqlite3_bind_value()], and
+** [sqlite3_value_dup()].
** The [sqlite3_value_blob | sqlite3_value_type()] family of
** interfaces require protected sqlite3_value objects.
*/
@@ -6200,15 +6244,20 @@ struct sqlite3_index_info {
** 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_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
/*
** CAPI3REF: Register A Virtual Table Implementation
@@ -6960,7 +7009,7 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_RESERVE 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
+#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
@@ -7019,8 +7068,7 @@ int sqlite3_status64(
** <dd>This parameter is the current amount of memory checked out
** using [sqlite3_malloc()], either directly or indirectly. The
** figure includes calls made to [sqlite3_malloc()] by the application
-** and internal memory usage by the SQLite library. Scratch memory
-** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache
+** and internal memory usage by the SQLite library. Auxiliary page-cache
** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in
** this parameter. The amount returned is the sum of the allocation
** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
@@ -7058,29 +7106,14 @@ int sqlite3_status64(
** *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>
-** <dd>This parameter returns the number of allocations used out of the
-** [scratch memory allocator] configured using
-** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not
-** in bytes. Since a single thread may only have one scratch allocation
-** outstanding at time, this parameter also reports the number of threads
-** using scratch memory at the same time.</dd>)^
+** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
+** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
-** <dd>This parameter returns the number of bytes of scratch memory
-** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
-** buffer and where forced to overflow to [sqlite3_malloc()]. The values
-** returned include overflows because the requested allocation was too
-** larger (that is, because the requested allocation was larger than the
-** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer
-** slots were available.
-** </dd>)^
-**
-** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
-** <dd>This parameter records the largest memory allocation request
-** handed to [scratch memory allocator]. Only the value returned in the
-** *pHighwater parameter to [sqlite3_status()] is of interest.
-** The value written into the *pCurrent parameter is undefined.</dd>)^
+** <dd>No longer used.</dd>
+**
+** [[SQLITE_STATUS_SCRATCH_SIZE]] <dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
+** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
** <dd>The *pHighwater parameter records the deepest parser stack.
@@ -7093,12 +7126,12 @@ int sqlite3_status64(
#define SQLITE_STATUS_MEMORY_USED 0
#define SQLITE_STATUS_PAGECACHE_USED 1
#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2
-#define SQLITE_STATUS_SCRATCH_USED 3
-#define SQLITE_STATUS_SCRATCH_OVERFLOW 4
+#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */
+#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */
#define SQLITE_STATUS_MALLOC_SIZE 5
#define SQLITE_STATUS_PARSER_STACK 6
#define SQLITE_STATUS_PAGECACHE_SIZE 7
-#define SQLITE_STATUS_SCRATCH_SIZE 8
+#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */
#define SQLITE_STATUS_MALLOC_COUNT 9
/*
diff --git a/third_party/sqlite/src/src/sqlite3ext.h b/third_party/sqlite/src/src/sqlite3ext.h
index a1abac8..bafb104 100644
--- a/third_party/sqlite/src/src/sqlite3ext.h
+++ b/third_party/sqlite/src/src/sqlite3ext.h
@@ -134,7 +134,7 @@ struct sqlite3_api_routines {
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
- char * (*snprintf)(int,char*,const char*,...);
+ char * (*xsnprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
@@ -246,7 +246,7 @@ struct sqlite3_api_routines {
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
- char *(*vsnprintf)(int,char*,const char*,va_list);
+ char *(*xvsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
/* Version 3.8.7 and later */
int (*auto_extension)(void(*)(void));
@@ -418,7 +418,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
-#define sqlite3_snprintf sqlite3_api->snprintf
+#define sqlite3_snprintf sqlite3_api->xsnprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
@@ -442,7 +442,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
-#define sqlite3_vsnprintf sqlite3_api->vsnprintf
+#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
@@ -518,7 +518,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
-#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
+#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
/* Version 3.8.7 and later */
#define sqlite3_auto_extension sqlite3_api->auto_extension
diff --git a/third_party/sqlite/src/src/sqliteInt.h b/third_party/sqlite/src/src/sqliteInt.h
index fcbcf8bb..d68da5a 100644
--- a/third_party/sqlite/src/src/sqliteInt.h
+++ b/third_party/sqlite/src/src/sqliteInt.h
@@ -51,17 +51,6 @@
#endif
/*
-** Make sure that rand_s() is available on Windows systems with MSVC 2005
-** or higher.
-*/
-#if defined(_MSC_VER) && _MSC_VER>=1400
-/* TODO(shess): Already defined by build/config/win/BUILD.gn */
-#ifndef _CRT_RAND_S
-# define _CRT_RAND_S
-#endif
-#endif
-
-/*
** Include the header file used to customize the compiler options for MSVC.
** This should be done first so that it can successfully prevent spurious
** compiler warnings due to subsequent content in this file and other files
@@ -458,6 +447,21 @@
#endif
/*
+** Some conditionals are optimizations only. In other words, if the
+** conditionals are replaced with a constant 1 (true) or 0 (false) then
+** the correct answer is still obtained, though perhaps not as quickly.
+**
+** The following macros mark these optimizations conditionals.
+*/
+#if defined(SQLITE_MUTATION_TEST)
+# define OK_IF_ALWAYS_TRUE(X) (1)
+# define OK_IF_ALWAYS_FALSE(X) (0)
+#else
+# define OK_IF_ALWAYS_TRUE(X) (X)
+# define OK_IF_ALWAYS_FALSE(X) (X)
+#endif
+
+/*
** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is
** defined. We need to defend against those failures when testing with
** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches
@@ -634,6 +638,15 @@
#endif
/*
+** 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.
+*/
+#if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+#error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+#endif
+
+/*
** GCC does not define the offsetof() macro so we'll have to do it
** ourselves.
*/
@@ -931,7 +944,7 @@ typedef INT16_TYPE LogEst;
** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
** the Select query generator tracing logic is turned on.
*/
-#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE)
+#if defined(SQLITE_ENABLE_SELECTTRACE)
# define SELECTTRACE_ENABLED 1
#else
# define SELECTTRACE_ENABLED 0
@@ -1207,6 +1220,7 @@ 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 */
/*
** The number of different kinds of things that can be limited
@@ -1238,9 +1252,9 @@ struct Lookaside {
u32 bDisable; /* Only operate the lookaside when zero */
u16 sz; /* Size of each buffer in bytes */
u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */
- int nOut; /* Number of buffers currently checked out */
- int mxOut; /* Highwater mark for nOut */
- int anStat[3]; /* 0: hits. 1: size misses. 2: full misses */
+ u32 nSlot; /* Number of lookaside slots allocated */
+ u32 anStat[3]; /* 0: hits. 1: size misses. 2: full misses */
+ LookasideSlot *pInit; /* List of buffers not previously used */
LookasideSlot *pFree; /* List of available buffers */
void *pStart; /* First byte of available memory space */
void *pEnd; /* First byte past end of available space */
@@ -1319,9 +1333,11 @@ struct sqlite3 {
sqlite3_mutex *mutex; /* Connection mutex */
Db *aDb; /* All backends */
int nDb; /* Number of backends currently in use */
- int flags; /* Miscellaneous flags. See below */
+ u32 mDbFlags; /* flags recording internal state */
+ u32 flags; /* flags settable by pragmas. See below */
i64 lastRowid; /* ROWID of most recent insert (see above) */
i64 szMmap; /* Default mmap_size setting */
+ 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 errMask; /* & result codes with this before returning */
@@ -1473,18 +1489,13 @@ struct sqlite3 {
#define SQLITE_ForeignKeys 0x00004000 /* Enforce foreign key constraints */
#define SQLITE_AutoIndex 0x00008000 /* Enable automatic indexes */
#define SQLITE_LoadExtension 0x00010000 /* Enable load_extension */
-#define SQLITE_EnableTrigger 0x00020000 /* True to enable triggers */
-#define SQLITE_DeferFKs 0x00040000 /* Defer all FK constraints */
-#define SQLITE_QueryOnly 0x00080000 /* Disable database changes */
-#define SQLITE_CellSizeCk 0x00100000 /* Check btree cell sizes on load */
-#define SQLITE_Fts3Tokenizer 0x00200000 /* Enable fts3_tokenizer(2) */
-#define SQLITE_EnableQPSG 0x00400000 /* Query Planner Stability Guarantee */
-/* The next four values are not used by PRAGMAs or by sqlite3_dbconfig() and
-** could be factored out into a separate bit vector of the sqlite3 object. */
-#define SQLITE_InternChanges 0x00800000 /* Uncommitted Hash table changes */
-#define SQLITE_LoadExtFunc 0x01000000 /* Enable load_extension() SQL func */
-#define SQLITE_PreferBuiltin 0x02000000 /* Preference to built-in funcs */
-#define SQLITE_Vacuum 0x04000000 /* Currently in a VACUUM */
+#define SQLITE_LoadExtFunc 0x00020000 /* Enable load_extension() SQL func */
+#define SQLITE_EnableTrigger 0x00040000 /* True to enable triggers */
+#define SQLITE_DeferFKs 0x00080000 /* Defer all FK constraints */
+#define SQLITE_QueryOnly 0x00100000 /* Disable database changes */
+#define SQLITE_CellSizeCk 0x00200000 /* Check btree cell sizes on load */
+#define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */
+#define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee */
/* Flags used only if debugging */
#ifdef SQLITE_DEBUG
#define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */
@@ -1494,6 +1505,12 @@ struct sqlite3 {
#define SQLITE_VdbeEQP 0x80000000 /* Debug EXPLAIN QUERY PLAN */
#endif
+/*
+** Allowed values for sqlite3.mDbFlags
+*/
+#define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */
+#define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */
+#define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */
/*
** Bits of the sqlite3.dbOptFlags field that are used by the
@@ -1504,16 +1521,15 @@ struct sqlite3 {
#define SQLITE_ColumnCache 0x0002 /* Column cache */
#define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */
#define SQLITE_FactorOutConst 0x0008 /* Constant factoring */
-/* not used 0x0010 // Was: SQLITE_IdxRealAsInt */
-#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
-#define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */
-#define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */
-#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
-#define SQLITE_Transitive 0x0200 /* Transitive constraints */
-#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
+#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_Stat34 0x0800 /* Use STAT3 or STAT4 data */
-#define SQLITE_CountOfView 0x1000 /* The count-of-view optimization */
-#define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */
+ /* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */
#define SQLITE_AllOpts 0xffff /* All optimizations */
/*
@@ -2044,8 +2060,8 @@ struct FKey {
struct KeyInfo {
u32 nRef; /* Number of references to this KeyInfo object */
u8 enc; /* Text encoding - one of the SQLITE_UTF* values */
- u16 nField; /* Number of key columns in the index */
- u16 nXField; /* Number of columns beyond the key columns */
+ u16 nKeyField; /* Number of key columns in the index */
+ u16 nAllField; /* Total columns, including key plus others */
sqlite3 *db; /* The database connection */
u8 *aSortOrder; /* Sort order for each column. */
CollSeq *aColl[1]; /* Collating sequence for each term of the key */
@@ -2092,8 +2108,8 @@ struct UnpackedRecord {
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) */
- i8 r1; /* Value to return if (lhs > rhs) */
- i8 r2; /* Value to return if (rhs < lhs) */
+ i8 r1; /* Value to return if (lhs < rhs) */
+ i8 r2; /* Value to return if (lhs > rhs) */
u8 eqSeen; /* True if an equality comparison has been seen */
};
@@ -2377,7 +2393,8 @@ struct Expr {
** TK_COLUMN: the value of p5 for OP_Column
** TK_AGG_FUNCTION: nesting depth */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
- Table *pTab; /* Table for TK_COLUMN expressions. */
+ Table *pTab; /* Table for TK_COLUMN expressions. Can be NULL
+ ** for a column of an index on an expression */
};
/*
@@ -2465,7 +2482,6 @@ 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 *zName; /* Token associated with this expression */
@@ -2990,7 +3006,7 @@ 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 */
- int addrCrTab; /* Address of OP_CreateTable opcode on CREATE TABLE */
+ int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */
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 */
@@ -3219,11 +3235,10 @@ struct DbFixer {
*/
struct StrAccum {
sqlite3 *db; /* Optional database for lookaside. Can be NULL */
- char *zBase; /* A base allocation. Not from malloc. */
char *zText; /* The string collected so far */
- u32 nChar; /* Length of the string so far */
u32 nAlloc; /* Amount of space allocated in zText */
u32 mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */
+ u32 nChar; /* Length of the string so far */
u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */
u8 printfFlags; /* SQLITE_PRINTF flags below */
};
@@ -3258,6 +3273,7 @@ struct Sqlite3Config {
int bFullMutex; /* True to enable full mutexing */
int bOpenUri; /* True to interpret filenames as URIs */
int bUseCis; /* Use covering indices for full-scans */
+ int bSmallMalloc; /* Avoid large memory allocations if true */
int mxStrlen; /* Maximum string length */
int neverCorrupt; /* Database is always well-formed */
int szLookaside; /* Default lookaside buffer size */
@@ -3271,9 +3287,6 @@ struct Sqlite3Config {
int mnReq, mxReq; /* Min and max heap requests sizes */
sqlite3_int64 szMmap; /* mmap() space per open file */
sqlite3_int64 mxMmap; /* Maximum value for szMmap */
- void *pScratch; /* Scratch memory */
- int szScratch; /* Size of each scratch buffer */
- int nScratch; /* Number of scratch buffers */
void *pPage; /* Page cache memory */
int szPage; /* Size of each page in pPage[] */
int nPage; /* Number of pages in pPage[] */
@@ -3360,6 +3373,7 @@ int sqlite3WalkSelectExpr(Walker*, Select*);
int sqlite3WalkSelectFrom(Walker*, Select*);
int sqlite3ExprWalkNoop(Walker*, Expr*);
int sqlite3SelectWalkNoop(Walker*, Select*);
+int sqlite3SelectWalkFail(Walker*, Select*);
#ifdef SQLITE_DEBUG
void sqlite3SelectWalkAssert2(Walker*, Select*);
#endif
@@ -3512,8 +3526,6 @@ void sqlite3DbFree(sqlite3*, void*);
void sqlite3DbFreeNN(sqlite3*, void*);
int sqlite3MallocSize(void*);
int sqlite3DbMallocSize(sqlite3*, void*);
-void *sqlite3ScratchMalloc(int);
-void sqlite3ScratchFree(void*);
void *sqlite3PageMalloc(int);
void sqlite3PageFree(void*);
void sqlite3MemSetDefault(void);
@@ -3569,6 +3581,7 @@ sqlite3_int64 sqlite3StatusValue(int);
void sqlite3StatusUp(int, int);
void sqlite3StatusDown(int, int);
void sqlite3StatusHighwater(int, int);
+int sqlite3LookasideUsed(sqlite3*,int*);
/* Access to mutexes used by sqlite3_status() */
sqlite3_mutex *sqlite3Pcache1Mutex(void);
@@ -4005,6 +4018,8 @@ int sqlite3ReadSchema(Parse *pParse);
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
+CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr);
+int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*);
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
Expr *sqlite3ExprSkipCollate(Expr*);
@@ -4288,7 +4303,8 @@ int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*);
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
int sqlite3JournalSize(sqlite3_vfs *);
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
int sqlite3JournalCreate(sqlite3_file *);
#endif
@@ -4374,8 +4390,7 @@ SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...);
#endif
#define MEMTYPE_HEAP 0x01 /* General heap allocations */
#define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */
-#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */
-#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
+#define MEMTYPE_PCACHE 0x04 /* Page cache allocations */
/*
** Threading interface
@@ -4385,6 +4400,9 @@ int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
int sqlite3ThreadJoin(SQLiteThread*, void**);
#endif
+#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)
+int sqlite3DbpageRegister(sqlite3*);
+#endif
#if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
int sqlite3DbstatRegister(sqlite3*);
#endif
diff --git a/third_party/sqlite/src/src/status.c b/third_party/sqlite/src/src/status.c
index 74548b7..f859dd4d 100644
--- a/third_party/sqlite/src/src/status.c
+++ b/third_party/sqlite/src/src/status.c
@@ -122,7 +122,6 @@ void sqlite3StatusHighwater(int op, int X){
: sqlite3MallocMutex()) );
assert( op==SQLITE_STATUS_MALLOC_SIZE
|| op==SQLITE_STATUS_PAGECACHE_SIZE
- || op==SQLITE_STATUS_SCRATCH_SIZE
|| op==SQLITE_STATUS_PARSER_STACK );
if( newValue>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = newValue;
@@ -172,6 +171,28 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
}
/*
+** Return the number of LookasideSlot elements on the linked list
+*/
+static u32 countLookasideSlots(LookasideSlot *p){
+ u32 cnt = 0;
+ while( p ){
+ p = p->pNext;
+ cnt++;
+ }
+ return cnt;
+}
+
+/*
+** Count the number of slots of lookaside memory that are outstanding
+*/
+int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
+ u32 nInit = countLookasideSlots(db->lookaside.pInit);
+ u32 nFree = countLookasideSlots(db->lookaside.pFree);
+ if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
+ return db->lookaside.nSlot - (nInit+nFree);
+}
+
+/*
** Query status information for a single database connection
*/
int sqlite3_db_status(
@@ -190,10 +211,15 @@ int sqlite3_db_status(
sqlite3_mutex_enter(db->mutex);
switch( op ){
case SQLITE_DBSTATUS_LOOKASIDE_USED: {
- *pCurrent = db->lookaside.nOut;
- *pHighwater = db->lookaside.mxOut;
+ *pCurrent = sqlite3LookasideUsed(db, pHighwater);
if( resetFlag ){
- db->lookaside.mxOut = db->lookaside.nOut;
+ LookasideSlot *p = db->lookaside.pFree;
+ if( p ){
+ while( p->pNext ) p = p->pNext;
+ p->pNext = db->lookaside.pInit;
+ db->lookaside.pInit = db->lookaside.pFree;
+ db->lookaside.pFree = 0;
+ }
}
break;
}
diff --git a/third_party/sqlite/src/src/tclsqlite.c b/third_party/sqlite/src/src/tclsqlite.c
index 2507e30..99b1808 100644
--- a/third_party/sqlite/src/src/tclsqlite.c
+++ b/third_party/sqlite/src/src/tclsqlite.c
@@ -14,17 +14,19 @@
**
** Compile-time options:
**
-** -DTCLSH=1 Add a "main()" routine that works as a tclsh.
+** -DTCLSH Add a "main()" routine that works as a tclsh.
**
-** -DSQLITE_TCLMD5 When used in conjuction with -DTCLSH=1, add
-** four new commands to the TCL interpreter for
-** generating MD5 checksums: md5, md5file,
-** md5-10x8, and md5file-10x8.
+** -DTCLSH_INIT_PROC=name
**
-** -DSQLITE_TEST When used in conjuction with -DTCLSH=1, add
-** hundreds of new commands used for testing
-** SQLite. This option implies -DSQLITE_TCLMD5.
-*/
+** Invoke name(interp) to initialize the Tcl interpreter.
+** If name(interp) returns a non-NULL string, then run
+** that string as a Tcl script to launch the application.
+** If name(interp) returns NULL, then run the regular
+** tclsh-emulator code.
+*/
+#ifdef TCLSH_INIT_PROC
+# define TCLSH 1
+#endif
/*
** If requested, include the SQLite compiler options file for MSVC.
@@ -3286,7 +3288,42 @@ static int SQLITE_TCLAPI DbObjCmd(
** Return the version string for this database.
*/
case DB_VERSION: {
- Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC);
+ int i;
+ for(i=2; i<objc; i++){
+ const char *zArg = Tcl_GetString(objv[i]);
+ /* Optional arguments to $db version are used for testing purpose */
+#ifdef SQLITE_TEST
+ /* $db version -use-legacy-prepare BOOLEAN
+ **
+ ** Turn the use of legacy sqlite3_prepare() on or off.
+ */
+ if( strcmp(zArg, "-use-legacy-prepare")==0 && i+1<objc ){
+ i++;
+ if( Tcl_GetBooleanFromObj(interp, objv[i], &pDb->bLegacyPrepare) ){
+ return TCL_ERROR;
+ }
+ }else
+
+ /* $db version -last-stmt-ptr
+ **
+ ** Return a string which is a hex encoding of the pointer to the
+ ** most recent sqlite3_stmt in the statement cache.
+ */
+ if( strcmp(zArg, "-last-stmt-ptr")==0 ){
+ char zBuf[100];
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%p",
+ pDb->stmtList ? pDb->stmtList->pStmt: 0);
+ Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
+ }else
+#endif /* SQLITE_TEST */
+ {
+ Tcl_AppendResult(interp, "unknown argument: ", zArg, (char*)0);
+ return TCL_ERROR;
+ }
+ }
+ if( i==2 ){
+ Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC);
+ }
break;
}
@@ -3546,710 +3583,56 @@ int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
#endif
-#ifdef TCLSH
-/*****************************************************************************
-** All of the code that follows is used to build standalone TCL interpreters
-** that are statically linked with SQLite. Enable these by compiling
-** with -DTCLSH=n where n can be 1 or 2. An n of 1 generates a standard
-** tclsh but with SQLite built in. An n of 2 generates the SQLite space
-** analysis program.
-*/
-
-#if defined(SQLITE_TEST) || defined(SQLITE_TCLMD5)
/*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest. This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MD5Init, call MD5Update as
- * needed on buffers full of bytes, and then call MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- */
-
-/*
- * If compiled on a machine that doesn't have a 32-bit integer,
- * you just set "uint32" to the appropriate datatype for an
- * unsigned 32-bit integer. For example:
- *
- * cc -Duint32='unsigned long' md5.c
- *
- */
-#ifndef uint32
-# define uint32 unsigned int
-#endif
-
-struct MD5Context {
- int isInit;
- uint32 buf[4];
- uint32 bits[2];
- unsigned char in[64];
-};
-typedef struct MD5Context MD5Context;
-
-/*
- * Note: this code is harmless on little-endian machines.
- */
-static void byteReverse (unsigned char *buf, unsigned longs){
- uint32 t;
- do {
- t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
- ((unsigned)buf[1]<<8 | buf[0]);
- *(uint32 *)buf = t;
- buf += 4;
- } while (--longs);
-}
-/* The four core functions - F1 is optimized somewhat */
-
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f, w, x, y, z, data, s) \
- ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
-
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data. MD5Update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void MD5Transform(uint32 buf[4], const uint32 in[16]){
- register uint32 a, b, c, d;
-
- a = buf[0];
- b = buf[1];
- c = buf[2];
- d = buf[3];
-
- MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
- MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
- MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
- MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
- MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
- MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
- MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
- MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
- MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
- MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
- MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
- MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
- MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
- MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
- MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
- MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
-
- MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
- MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
- MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
- MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
- MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
- MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
- MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
- MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
- MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
- MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
- MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
- MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
- MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
- MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
- MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
- MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
-
- MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
- MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
- MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
- MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
- MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
- MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
- MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
- MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
- MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
- MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
- MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
- MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
- MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
- MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
- MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
- MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
-
- MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
- MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
- MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
- MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
- MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
- MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
- MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
- MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
- MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
- MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
- MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
- MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
- MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
- MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
- MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
- MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
-
- buf[0] += a;
- buf[1] += b;
- buf[2] += c;
- buf[3] += d;
-}
-
-/*
- * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-static void MD5Init(MD5Context *ctx){
- ctx->isInit = 1;
- ctx->buf[0] = 0x67452301;
- ctx->buf[1] = 0xefcdab89;
- ctx->buf[2] = 0x98badcfe;
- ctx->buf[3] = 0x10325476;
- ctx->bits[0] = 0;
- ctx->bits[1] = 0;
-}
-
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-static
-void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
- uint32 t;
-
- /* Update bitcount */
-
- t = ctx->bits[0];
- if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
- ctx->bits[1]++; /* Carry from low to high */
- ctx->bits[1] += len >> 29;
-
- t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
-
- /* Handle any leading odd-sized chunks */
-
- if ( t ) {
- unsigned char *p = (unsigned char *)ctx->in + t;
-
- t = 64-t;
- if (len < t) {
- memcpy(p, buf, len);
- return;
- }
- memcpy(p, buf, t);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32 *)ctx->in);
- buf += t;
- len -= t;
- }
-
- /* Process data in 64-byte chunks */
-
- while (len >= 64) {
- memcpy(ctx->in, buf, 64);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32 *)ctx->in);
- buf += 64;
- len -= 64;
- }
-
- /* Handle any remaining bytes of data. */
-
- memcpy(ctx->in, buf, len);
-}
-
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-static void MD5Final(unsigned char digest[16], MD5Context *ctx){
- unsigned count;
- unsigned char *p;
-
- /* Compute number of bytes mod 64 */
- count = (ctx->bits[0] >> 3) & 0x3F;
-
- /* Set the first char of padding to 0x80. This is safe since there is
- always at least one byte free */
- p = ctx->in + count;
- *p++ = 0x80;
-
- /* Bytes of padding needed to make 64 bytes */
- count = 64 - 1 - count;
-
- /* Pad out to 56 mod 64 */
- if (count < 8) {
- /* Two lots of padding: Pad the first block to 64 bytes */
- memset(p, 0, count);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (uint32 *)ctx->in);
-
- /* Now fill the next block with 56 bytes */
- memset(ctx->in, 0, 56);
- } else {
- /* Pad block to 56 bytes */
- memset(p, 0, count-8);
- }
- byteReverse(ctx->in, 14);
-
- /* Append length in bits and transform */
- memcpy(ctx->in + 14*4, ctx->bits, 8);
-
- MD5Transform(ctx->buf, (uint32 *)ctx->in);
- byteReverse((unsigned char *)ctx->buf, 4);
- memcpy(digest, ctx->buf, 16);
-}
-
-/*
-** Convert a 128-bit MD5 digest into a 32-digit base-16 number.
-*/
-static void MD5DigestToBase16(unsigned char *digest, char *zBuf){
- static char const zEncode[] = "0123456789abcdef";
- int i, j;
-
- for(j=i=0; i<16; i++){
- int a = digest[i];
- zBuf[j++] = zEncode[(a>>4)&0xf];
- zBuf[j++] = zEncode[a & 0xf];
- }
- zBuf[j] = 0;
-}
-
-
-/*
-** Convert a 128-bit MD5 digest into sequency of eight 5-digit integers
-** each representing 16 bits of the digest and separated from each
-** other by a "-" character.
-*/
-static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
- int i, j;
- unsigned int x;
- for(i=j=0; i<16; i+=2){
- x = digest[i]*256 + digest[i+1];
- if( i>0 ) zDigest[j++] = '-';
- sqlite3_snprintf(50-j, &zDigest[j], "%05u", x);
- j += 5;
- }
- zDigest[j] = 0;
-}
-
-/*
-** A TCL command for md5. The argument is the text to be hashed. The
-** Result is the hash in base64.
-*/
-static int SQLITE_TCLAPI md5_cmd(
- void*cd,
- Tcl_Interp *interp,
- int argc,
- const char **argv
-){
- MD5Context ctx;
- unsigned char digest[16];
- char zBuf[50];
- void (*converter)(unsigned char*, char*);
-
- if( argc!=2 ){
- Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
- " TEXT\"", (char*)0);
- return TCL_ERROR;
- }
- MD5Init(&ctx);
- MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1]));
- MD5Final(digest, &ctx);
- converter = (void(*)(unsigned char*,char*))cd;
- converter(digest, zBuf);
- Tcl_AppendResult(interp, zBuf, (char*)0);
- return TCL_OK;
-}
-
-/*
-** A TCL command to take the md5 hash of a file. The argument is the
-** name of the file.
-*/
-static int SQLITE_TCLAPI md5file_cmd(
- void*cd,
- Tcl_Interp *interp,
- int argc,
- const char **argv
-){
- FILE *in;
- MD5Context ctx;
- void (*converter)(unsigned char*, char*);
- unsigned char digest[16];
- char zBuf[10240];
-
- if( argc!=2 ){
- Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
- " FILENAME\"", (char*)0);
- return TCL_ERROR;
- }
- in = fopen(argv[1],"rb");
- if( in==0 ){
- Tcl_AppendResult(interp,"unable to open file \"", argv[1],
- "\" for reading", (char*)0);
- return TCL_ERROR;
- }
- MD5Init(&ctx);
- for(;;){
- int n;
- n = (int)fread(zBuf, 1, sizeof(zBuf), in);
- if( n<=0 ) break;
- MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
- }
- fclose(in);
- MD5Final(digest, &ctx);
- converter = (void(*)(unsigned char*,char*))cd;
- converter(digest, zBuf);
- Tcl_AppendResult(interp, zBuf, (char*)0);
- return TCL_OK;
-}
-
-/*
-** Register the four new TCL commands for generating MD5 checksums
-** with the TCL interpreter.
+** If the TCLSH macro is defined, add code to make a stand-alone program.
*/
-int Md5_Init(Tcl_Interp *interp){
- Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd,
- MD5DigestToBase16, 0);
- Tcl_CreateCommand(interp, "md5-10x8", (Tcl_CmdProc*)md5_cmd,
- MD5DigestToBase10x8, 0);
- Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd,
- MD5DigestToBase16, 0);
- Tcl_CreateCommand(interp, "md5file-10x8", (Tcl_CmdProc*)md5file_cmd,
- MD5DigestToBase10x8, 0);
- return TCL_OK;
-}
-#endif /* defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) */
+#if defined(TCLSH)
-#if defined(SQLITE_TEST)
-/*
-** During testing, the special md5sum() aggregate function is available.
-** inside SQLite. The following routines implement that function.
+/* This is the main routine for an ordinary TCL shell. If there are
+** are arguments, run the first argument as a script. Otherwise,
+** read TCL commands from standard input
*/
-static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){
- MD5Context *p;
- int i;
- if( argc<1 ) return;
- p = sqlite3_aggregate_context(context, sizeof(*p));
- if( p==0 ) return;
- if( !p->isInit ){
- MD5Init(p);
- }
- for(i=0; i<argc; i++){
- const char *zData = (char*)sqlite3_value_text(argv[i]);
- if( zData ){
- MD5Update(p, (unsigned char*)zData, (int)strlen(zData));
- }
- }
-}
-static void md5finalize(sqlite3_context *context){
- MD5Context *p;
- unsigned char digest[16];
- char zBuf[33];
- p = sqlite3_aggregate_context(context, sizeof(*p));
- MD5Final(digest,p);
- MD5DigestToBase16(digest, zBuf);
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
-}
-int Md5_Register(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pThunk
-){
- int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
- md5step, md5finalize);
- sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */
- return rc;
-}
-#endif /* defined(SQLITE_TEST) */
-
-
-/*
-** If the macro TCLSH is one, then put in code this for the
-** "main" routine that will initialize Tcl and take input from
-** standard input, or if a file is named on the command line
-** the TCL interpreter reads and evaluates that file.
-*/
-#if TCLSH==1
static const char *tclsh_main_loop(void){
static const char zMainloop[] =
- "set line {}\n"
- "while {![eof stdin]} {\n"
- "if {$line!=\"\"} {\n"
- "puts -nonewline \"> \"\n"
- "} else {\n"
- "puts -nonewline \"% \"\n"
- "}\n"
- "flush stdout\n"
- "append line [gets stdin]\n"
- "if {[info complete $line]} {\n"
- "if {[catch {uplevel #0 $line} result]} {\n"
- "puts stderr \"Error: $result\"\n"
- "} elseif {$result!=\"\"} {\n"
- "puts $result\n"
+ "if {[llength $argv]>=1} {\n"
+ "set argv0 [lindex $argv 0]\n"
+ "set argv [lrange $argv 1 end]\n"
+ "source $argv0\n"
+ "} else {\n"
+ "set line {}\n"
+ "while {![eof stdin]} {\n"
+ "if {$line!=\"\"} {\n"
+ "puts -nonewline \"> \"\n"
+ "} else {\n"
+ "puts -nonewline \"% \"\n"
+ "}\n"
+ "flush stdout\n"
+ "append line [gets stdin]\n"
+ "if {[info complete $line]} {\n"
+ "if {[catch {uplevel #0 $line} result]} {\n"
+ "puts stderr \"Error: $result\"\n"
+ "} elseif {$result!=\"\"} {\n"
+ "puts $result\n"
+ "}\n"
+ "set line {}\n"
+ "} else {\n"
+ "append line \\n\n"
"}\n"
- "set line {}\n"
- "} else {\n"
- "append line \\n\n"
"}\n"
"}\n"
;
return zMainloop;
}
-#endif
-#if TCLSH==2
-static const char *tclsh_main_loop(void);
-#endif
-
-#ifdef SQLITE_TEST
-static void init_all(Tcl_Interp *);
-static int SQLITE_TCLAPI init_all_cmd(
- ClientData cd,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]
-){
-
- Tcl_Interp *slave;
- if( objc!=2 ){
- Tcl_WrongNumArgs(interp, 1, objv, "SLAVE");
- return TCL_ERROR;
- }
-
- slave = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
- if( !slave ){
- return TCL_ERROR;
- }
-
- init_all(slave);
- return TCL_OK;
-}
-
-/*
-** Tclcmd: db_use_legacy_prepare DB BOOLEAN
-**
-** The first argument to this command must be a database command created by
-** [sqlite3]. If the second argument is true, then the handle is configured
-** to use the sqlite3_prepare_v2() function to prepare statements. If it
-** is false, sqlite3_prepare().
-*/
-static int SQLITE_TCLAPI db_use_legacy_prepare_cmd(
- ClientData cd,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]
-){
- Tcl_CmdInfo cmdInfo;
- SqliteDb *pDb;
- int bPrepare;
-
- if( objc!=3 ){
- Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN");
- return TCL_ERROR;
- }
-
- if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
- Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0);
- return TCL_ERROR;
- }
- pDb = (SqliteDb*)cmdInfo.objClientData;
- if( Tcl_GetBooleanFromObj(interp, objv[2], &bPrepare) ){
- return TCL_ERROR;
- }
-
- pDb->bLegacyPrepare = bPrepare;
-
- Tcl_ResetResult(interp);
- return TCL_OK;
-}
-
-/*
-** Tclcmd: db_last_stmt_ptr DB
-**
-** If the statement cache associated with database DB is not empty,
-** return the text representation of the most recently used statement
-** handle.
-*/
-static int SQLITE_TCLAPI db_last_stmt_ptr(
- ClientData cd,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]
-){
- extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*);
- Tcl_CmdInfo cmdInfo;
- SqliteDb *pDb;
- sqlite3_stmt *pStmt = 0;
- char zBuf[100];
-
- if( objc!=2 ){
- Tcl_WrongNumArgs(interp, 1, objv, "DB");
- return TCL_ERROR;
- }
-
- if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
- Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0);
- return TCL_ERROR;
- }
- pDb = (SqliteDb*)cmdInfo.objClientData;
-
- if( pDb->stmtList ) pStmt = pDb->stmtList->pStmt;
- if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ){
- return TCL_ERROR;
- }
- Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
-
- return TCL_OK;
-}
-#endif /* SQLITE_TEST */
-
-/*
-** Configure the interpreter passed as the first argument to have access
-** to the commands and linked variables that make up:
-**
-** * the [sqlite3] extension itself,
-**
-** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
-**
-** * If SQLITE_TEST is set, the various test interfaces used by the Tcl
-** test suite.
-*/
-static void init_all(Tcl_Interp *interp){
- Sqlite3_Init(interp);
-
-#if defined(SQLITE_TEST) || defined(SQLITE_TCLMD5)
- Md5_Init(interp);
-#endif
-
-#ifdef SQLITE_TEST
- {
- extern int Sqliteconfig_Init(Tcl_Interp*);
- extern int Sqlitetest1_Init(Tcl_Interp*);
- extern int Sqlitetest2_Init(Tcl_Interp*);
- extern int Sqlitetest3_Init(Tcl_Interp*);
- extern int Sqlitetest4_Init(Tcl_Interp*);
- extern int Sqlitetest5_Init(Tcl_Interp*);
- extern int Sqlitetest6_Init(Tcl_Interp*);
- extern int Sqlitetest7_Init(Tcl_Interp*);
- extern int Sqlitetest8_Init(Tcl_Interp*);
- extern int Sqlitetest9_Init(Tcl_Interp*);
- extern int Sqlitetestasync_Init(Tcl_Interp*);
- extern int Sqlitetest_autoext_Init(Tcl_Interp*);
- extern int Sqlitetest_blob_Init(Tcl_Interp*);
- extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
- extern int Sqlitetest_func_Init(Tcl_Interp*);
- extern int Sqlitetest_hexio_Init(Tcl_Interp*);
- extern int Sqlitetest_init_Init(Tcl_Interp*);
- extern int Sqlitetest_malloc_Init(Tcl_Interp*);
- extern int Sqlitetest_mutex_Init(Tcl_Interp*);
- extern int Sqlitetestschema_Init(Tcl_Interp*);
- extern int Sqlitetestsse_Init(Tcl_Interp*);
- extern int Sqlitetesttclvar_Init(Tcl_Interp*);
- extern int Sqlitetestfs_Init(Tcl_Interp*);
- extern int SqlitetestThread_Init(Tcl_Interp*);
- extern int SqlitetestOnefile_Init();
- extern int SqlitetestOsinst_Init(Tcl_Interp*);
- extern int Sqlitetestbackup_Init(Tcl_Interp*);
- extern int Sqlitetestintarray_Init(Tcl_Interp*);
- extern int Sqlitetestvfs_Init(Tcl_Interp *);
- extern int Sqlitetestrtree_Init(Tcl_Interp*);
- extern int Sqlitequota_Init(Tcl_Interp*);
- extern int Sqlitemultiplex_Init(Tcl_Interp*);
- extern int SqliteSuperlock_Init(Tcl_Interp*);
- extern int SqlitetestSyscall_Init(Tcl_Interp*);
-#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
- extern int TestSession_Init(Tcl_Interp*);
-#endif
- extern int Fts5tcl_Init(Tcl_Interp *);
- extern int SqliteRbu_Init(Tcl_Interp*);
- extern int Sqlitetesttcl_Init(Tcl_Interp*);
-#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
- extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
-#endif
-
-#ifdef SQLITE_ENABLE_ZIPVFS
- extern int Zipvfs_Init(Tcl_Interp*);
- Zipvfs_Init(interp);
-#endif
-
- Sqliteconfig_Init(interp);
- Sqlitetest1_Init(interp);
- Sqlitetest2_Init(interp);
- Sqlitetest3_Init(interp);
- Sqlitetest4_Init(interp);
- Sqlitetest5_Init(interp);
- Sqlitetest6_Init(interp);
- Sqlitetest7_Init(interp);
- Sqlitetest8_Init(interp);
- Sqlitetest9_Init(interp);
- Sqlitetestasync_Init(interp);
- Sqlitetest_autoext_Init(interp);
- Sqlitetest_blob_Init(interp);
- Sqlitetest_demovfs_Init(interp);
- Sqlitetest_func_Init(interp);
- Sqlitetest_hexio_Init(interp);
- Sqlitetest_init_Init(interp);
- Sqlitetest_malloc_Init(interp);
- Sqlitetest_mutex_Init(interp);
- Sqlitetestschema_Init(interp);
- Sqlitetesttclvar_Init(interp);
- Sqlitetestfs_Init(interp);
- SqlitetestThread_Init(interp);
- SqlitetestOnefile_Init();
- SqlitetestOsinst_Init(interp);
- Sqlitetestbackup_Init(interp);
- Sqlitetestintarray_Init(interp);
- Sqlitetestvfs_Init(interp);
- Sqlitetestrtree_Init(interp);
- Sqlitequota_Init(interp);
- Sqlitemultiplex_Init(interp);
- SqliteSuperlock_Init(interp);
- SqlitetestSyscall_Init(interp);
-#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
- TestSession_Init(interp);
-#endif
- Fts5tcl_Init(interp);
- SqliteRbu_Init(interp);
- Sqlitetesttcl_Init(interp);
-
-#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
- Sqlitetestfts3_Init(interp);
-#endif
-
- Tcl_CreateObjCommand(
- interp, "load_testfixture_extensions", init_all_cmd, 0, 0
- );
- Tcl_CreateObjCommand(
- interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0
- );
- Tcl_CreateObjCommand(
- interp, "db_last_stmt_ptr", db_last_stmt_ptr, 0, 0
- );
-
-#ifdef SQLITE_SSE
- Sqlitetestsse_Init(interp);
-#endif
- }
-#endif
-}
-
-/* Needed for the setrlimit() system call on unix */
-#if defined(unix)
-#include <sys/resource.h>
-#endif
#define TCLSH_MAIN main /* Needed to fake out mktclapp */
int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){
Tcl_Interp *interp;
+ int i;
+ const char *zScript = 0;
+ char zArgc[32];
+#if defined(TCLSH_INIT_PROC)
+ extern const char *TCLSH_INIT_PROC(Tcl_Interp*);
+#endif
#if !defined(_WIN32_WCE)
if( getenv("BREAK") ){
@@ -4260,17 +3643,6 @@ int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){
}
#endif
- /* Since the primary use case for this binary is testing of SQLite,
- ** be sure to generate core files if we crash */
-#if defined(SQLITE_TEST) && defined(unix)
- { struct rlimit x;
- getrlimit(RLIMIT_CORE, &x);
- x.rlim_cur = x.rlim_max;
- setrlimit(RLIMIT_CORE, &x);
- }
-#endif /* SQLITE_TEST && unix */
-
-
/* Call sqlite3_shutdown() once before doing anything else. This is to
** test that sqlite3_shutdown() can be safely called by a process before
** sqlite3_initialize() is. */
@@ -4279,32 +3651,27 @@ int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){
Tcl_FindExecutable(argv[0]);
Tcl_SetSystemEncoding(NULL, "utf-8");
interp = Tcl_CreateInterp();
+ Sqlite3_Init(interp);
-#if TCLSH==2
- sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
+ sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-1);
+ Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
+ Tcl_SetVar(interp,"argv0",argv[0],TCL_GLOBAL_ONLY);
+ Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
+ for(i=1; i<argc; i++){
+ Tcl_SetVar(interp, "argv", argv[i],
+ TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
+ }
+#if defined(TCLSH_INIT_PROC)
+ zScript = TCLSH_INIT_PROC(interp);
#endif
-
- init_all(interp);
- if( argc>=2 ){
- int i;
- char zArgc[32];
- sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH));
- Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
- Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
- Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
- for(i=3-TCLSH; i<argc; i++){
- Tcl_SetVar(interp, "argv", argv[i],
- TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
- }
- if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
- const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
- if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp);
- fprintf(stderr,"%s: %s\n", *argv, zInfo);
- return 1;
- }
+ if( zScript==0 ){
+ zScript = tclsh_main_loop();
}
- if( TCLSH==2 || argc<=1 ){
- Tcl_GlobalEval(interp, tclsh_main_loop());
+ if( Tcl_GlobalEval(interp, zScript)!=TCL_OK ){
+ const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
+ if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp);
+ fprintf(stderr,"%s: %s\n", *argv, zInfo);
+ return 1;
}
return 0;
}
diff --git a/third_party/sqlite/src/src/test1.c b/third_party/sqlite/src/src/test1.c
index 4122651..6677826 100644
--- a/third_party/sqlite/src/src/test1.c
+++ b/third_party/sqlite/src/src/test1.c
@@ -2554,6 +2554,46 @@ static int SQLITE_TCLAPI test_delete_database(
}
/*
+** Usage: atomic_batch_write PATH
+*/
+static int SQLITE_TCLAPI test_atomic_batch_write(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ char *zFile = 0; /* Path to file to test */
+ sqlite3 *db = 0; /* Database handle */
+ sqlite3_file *pFd = 0; /* SQLite fd open on zFile */
+ int bRes = 0; /* Integer result of this command */
+ int dc = 0; /* Device-characteristics mask */
+ int rc; /* sqlite3_open() return code */
+
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "PATH");
+ return TCL_ERROR;
+ }
+ zFile = Tcl_GetString(objv[1]);
+
+ rc = sqlite3_open(zFile, &db);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
+ sqlite3_close(db);
+ return TCL_ERROR;
+ }
+
+ rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFd);
+ dc = pFd->pMethods->xDeviceCharacteristics(pFd);
+ if( dc & SQLITE_IOCAP_BATCH_ATOMIC ){
+ bRes = 1;
+ }
+
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(bRes));
+ sqlite3_close(db);
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_next_stmt DB STMT
**
** Return the next statment in sequence after STMT.
@@ -6861,7 +6901,6 @@ static int SQLITE_TCLAPI optimization_control(
{ "cover-idx-scan", SQLITE_CoverIdxScan },
{ "order-by-idx-join", SQLITE_OrderByIdxJoin },
{ "transitive", SQLITE_Transitive },
- { "subquery-coroutine", SQLITE_SubqCoroutine },
{ "omit-noop-join", SQLITE_OmitNoopJoin },
{ "stat3", SQLITE_Stat34 },
{ "stat4", SQLITE_Stat34 },
@@ -7376,6 +7415,35 @@ static int SQLITE_TCLAPI test_dbconfig_maindbname_icecube(
}
/*
+** Usage: sqlite3_mmap_warm DB DBNAME
+*/
+static int SQLITE_TCLAPI test_mmap_warm(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
+ extern int sqlite3_mmap_warm(sqlite3 *db, const char *);
+
+ if( objc!=2 && objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB ?DBNAME?");
+ return TCL_ERROR;
+ }else{
+ int rc;
+ sqlite3 *db;
+ const char *zDb = 0;
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ if( objc==3 ){
+ zDb = Tcl_GetString(objv[2]);
+ }
+ rc = sqlite3_mmap_warm(db, zDb);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
+ return TCL_OK;
+ }
+}
+
+/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest1_Init(Tcl_Interp *interp){
@@ -7644,7 +7712,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 },
{ "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
#endif
- { "sqlite3_delete_database", test_delete_database, 0 },
+ { "sqlite3_delete_database", test_delete_database, 0 },
+ { "atomic_batch_write", test_atomic_batch_write, 0 },
+ { "sqlite3_mmap_warm", test_mmap_warm, 0 },
};
static int bitmask_size = sizeof(Bitmask)*8;
static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
diff --git a/third_party/sqlite/src/src/test6.c b/third_party/sqlite/src/src/test6.c
index 6821850..191fe05 100644
--- a/third_party/sqlite/src/src/test6.c
+++ b/third_party/sqlite/src/src/test6.c
@@ -736,6 +736,7 @@ static int processDevSymArgs(
{ "sequential", SQLITE_IOCAP_SEQUENTIAL },
{ "safe_append", SQLITE_IOCAP_SAFE_APPEND },
{ "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE },
+ { "batch-atomic", SQLITE_IOCAP_BATCH_ATOMIC },
{ 0, 0 }
};
@@ -976,7 +977,30 @@ static int SQLITE_TCLAPI devSymObjCmd(
devsym_register(iDc, iSectorSize);
return TCL_OK;
+}
+/*
+** tclcmd: sqlite3_crash_on_write N
+*/
+static int SQLITE_TCLAPI writeCrashObjCmd(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ void devsym_crash_on_write(int);
+ int nWrite = 0;
+
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "NWRITE");
+ return TCL_ERROR;
+ }
+ if( Tcl_GetIntFromObj(interp, objv[1], &nWrite) ){
+ return TCL_ERROR;
+ }
+
+ devsym_crash_on_write(nWrite);
+ return TCL_OK;
}
/*
@@ -1068,6 +1092,7 @@ int Sqlitetest6_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "sqlite3_crash_now", crashNowCmd, 0, 0);
Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0);
+ Tcl_CreateObjCommand(interp, "sqlite3_crash_on_write", writeCrashObjCmd,0,0);
Tcl_CreateObjCommand(interp, "unregister_devsim", dsUnregisterObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0);
diff --git a/third_party/sqlite/src/src/test8.c b/third_party/sqlite/src/src/test8.c
index 1a89e47..b54759f 100644
--- a/third_party/sqlite/src/src/test8.c
+++ b/third_party/sqlite/src/src/test8.c
@@ -897,17 +897,18 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
case SQLITE_INDEX_CONSTRAINT_REGEXP:
zOp = "regexp"; break;
}
- if( zOp[0]=='L' ){
- zNew = sqlite3_mprintf(" %s %s LIKE (SELECT '%%'||?||'%%')",
- zSep, zNewCol);
- } else {
- zNew = sqlite3_mprintf(" %s %s %s ?", zSep, zNewCol, zOp);
+ if( zOp ){
+ if( zOp[0]=='L' ){
+ zNew = sqlite3_mprintf(" %s %s LIKE (SELECT '%%'||?||'%%')",
+ zSep, zNewCol);
+ } else {
+ zNew = sqlite3_mprintf(" %s %s %s ?", zSep, zNewCol, zOp);
+ }
+ string_concat(&zQuery, zNew, 1, &rc);
+ zSep = "AND";
+ pUsage->argvIndex = ++nArg;
+ pUsage->omit = 1;
}
- string_concat(&zQuery, zNew, 1, &rc);
-
- zSep = "AND";
- pUsage->argvIndex = ++nArg;
- pUsage->omit = 1;
}
}
diff --git a/third_party/sqlite/src/src/test_bestindex.c b/third_party/sqlite/src/src/test_bestindex.c
index f0cef49..581f5b1 100644
--- a/third_party/sqlite/src/src/test_bestindex.c
+++ b/third_party/sqlite/src/src/test_bestindex.c
@@ -414,6 +414,16 @@ static int tclBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
zOp = "glob"; break;
case SQLITE_INDEX_CONSTRAINT_REGEXP:
zOp = "regexp"; break;
+ case SQLITE_INDEX_CONSTRAINT_NE:
+ zOp = "ne"; break;
+ case SQLITE_INDEX_CONSTRAINT_ISNOT:
+ zOp = "isnot"; break;
+ case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
+ zOp = "isnotnull"; break;
+ case SQLITE_INDEX_CONSTRAINT_ISNULL:
+ zOp = "isnull"; break;
+ case SQLITE_INDEX_CONSTRAINT_IS:
+ zOp = "is"; break;
}
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("op", -1));
diff --git a/third_party/sqlite/src/src/test_config.c b/third_party/sqlite/src/src/test_config.c
index b794f6c..9539292 100644
--- a/third_party/sqlite/src/src/test_config.c
+++ b/third_party/sqlite/src/src/test_config.c
@@ -214,6 +214,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "json1", "0", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_HAS_CODEC
+ Tcl_SetVar2(interp, "sqlite_options", "has_codec", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "has_codec", "0", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
Tcl_SetVar2(interp, "sqlite_options", "like_match_blobs", "0", TCL_GLOBAL_ONLY);
#else
diff --git a/third_party/sqlite/src/src/test_devsym.c b/third_party/sqlite/src/src/test_devsym.c
index a436bb5..22542b7 100644
--- a/third_party/sqlite/src/src/test_devsym.c
+++ b/third_party/sqlite/src/src/test_devsym.c
@@ -28,6 +28,7 @@
** Name used to identify this VFS.
*/
#define DEVSYM_VFS_NAME "devsym"
+#define WRITECRASH_NAME "writecrash"
typedef struct devsym_file devsym_file;
struct devsym_file {
@@ -72,61 +73,13 @@ static int devsymRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int devsymSleep(sqlite3_vfs*, int microseconds);
static int devsymCurrentTime(sqlite3_vfs*, double*);
-static sqlite3_vfs devsym_vfs = {
- 2, /* iVersion */
- sizeof(devsym_file), /* szOsFile */
- DEVSYM_MAX_PATHNAME, /* mxPathname */
- 0, /* pNext */
- DEVSYM_VFS_NAME, /* zName */
- 0, /* pAppData */
- devsymOpen, /* xOpen */
- devsymDelete, /* xDelete */
- devsymAccess, /* xAccess */
- devsymFullPathname, /* xFullPathname */
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
- devsymDlOpen, /* xDlOpen */
- devsymDlError, /* xDlError */
- devsymDlSym, /* xDlSym */
- devsymDlClose, /* xDlClose */
-#else
- 0, /* xDlOpen */
- 0, /* xDlError */
- 0, /* xDlSym */
- 0, /* xDlClose */
-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
- devsymRandomness, /* xRandomness */
- devsymSleep, /* xSleep */
- devsymCurrentTime, /* xCurrentTime */
- 0, /* xGetLastError */
- 0 /* xCurrentTimeInt64 */
-};
-
-static sqlite3_io_methods devsym_io_methods = {
- 2, /* iVersion */
- devsymClose, /* xClose */
- devsymRead, /* xRead */
- devsymWrite, /* xWrite */
- devsymTruncate, /* xTruncate */
- devsymSync, /* xSync */
- devsymFileSize, /* xFileSize */
- devsymLock, /* xLock */
- devsymUnlock, /* xUnlock */
- devsymCheckReservedLock, /* xCheckReservedLock */
- devsymFileControl, /* xFileControl */
- devsymSectorSize, /* xSectorSize */
- devsymDeviceCharacteristics, /* xDeviceCharacteristics */
- devsymShmMap, /* xShmMap */
- devsymShmLock, /* xShmLock */
- devsymShmBarrier, /* xShmBarrier */
- devsymShmUnmap /* xShmUnmap */
-};
-
struct DevsymGlobal {
sqlite3_vfs *pVfs;
int iDeviceChar;
int iSectorSize;
+ int nWriteCrash;
};
-struct DevsymGlobal g = {0, 0, 512};
+struct DevsymGlobal g = {0, 0, 512, 0};
/*
** Close an devsym-file.
@@ -271,6 +224,26 @@ static int devsymOpen(
int flags,
int *pOutFlags
){
+static sqlite3_io_methods devsym_io_methods = {
+ 2, /* iVersion */
+ devsymClose, /* xClose */
+ devsymRead, /* xRead */
+ devsymWrite, /* xWrite */
+ devsymTruncate, /* xTruncate */
+ devsymSync, /* xSync */
+ devsymFileSize, /* xFileSize */
+ devsymLock, /* xLock */
+ devsymUnlock, /* xUnlock */
+ devsymCheckReservedLock, /* xCheckReservedLock */
+ devsymFileControl, /* xFileControl */
+ devsymSectorSize, /* xSectorSize */
+ devsymDeviceCharacteristics, /* xDeviceCharacteristics */
+ devsymShmMap, /* xShmMap */
+ devsymShmLock, /* xShmLock */
+ devsymShmBarrier, /* xShmBarrier */
+ devsymShmUnmap /* xShmUnmap */
+};
+
int rc;
devsym_file *p = (devsym_file *)pFile;
p->pReal = (sqlite3_file *)&p[1];
@@ -372,6 +345,137 @@ static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
}
+/*
+** Return the sector-size in bytes for an writecrash-file.
+*/
+static int writecrashSectorSize(sqlite3_file *pFile){
+ devsym_file *p = (devsym_file *)pFile;
+ return sqlite3OsSectorSize(p->pReal);
+}
+
+/*
+** Return the device characteristic flags supported by an writecrash-file.
+*/
+static int writecrashDeviceCharacteristics(sqlite3_file *pFile){
+ devsym_file *p = (devsym_file *)pFile;
+ return sqlite3OsDeviceCharacteristics(p->pReal);
+}
+
+/*
+** Write data to an writecrash-file.
+*/
+static int writecrashWrite(
+ sqlite3_file *pFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ devsym_file *p = (devsym_file *)pFile;
+ if( g.nWriteCrash>0 ){
+ g.nWriteCrash--;
+ if( g.nWriteCrash==0 ) abort();
+ }
+ return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
+}
+
+/*
+** Open an writecrash file handle.
+*/
+static int writecrashOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+static sqlite3_io_methods writecrash_io_methods = {
+ 2, /* iVersion */
+ devsymClose, /* xClose */
+ devsymRead, /* xRead */
+ writecrashWrite, /* xWrite */
+ devsymTruncate, /* xTruncate */
+ devsymSync, /* xSync */
+ devsymFileSize, /* xFileSize */
+ devsymLock, /* xLock */
+ devsymUnlock, /* xUnlock */
+ devsymCheckReservedLock, /* xCheckReservedLock */
+ devsymFileControl, /* xFileControl */
+ writecrashSectorSize, /* xSectorSize */
+ writecrashDeviceCharacteristics, /* xDeviceCharacteristics */
+ devsymShmMap, /* xShmMap */
+ devsymShmLock, /* xShmLock */
+ devsymShmBarrier, /* xShmBarrier */
+ devsymShmUnmap /* xShmUnmap */
+};
+
+ int rc;
+ devsym_file *p = (devsym_file *)pFile;
+ p->pReal = (sqlite3_file *)&p[1];
+ rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
+ if( p->pReal->pMethods ){
+ pFile->pMethods = &writecrash_io_methods;
+ }
+ return rc;
+}
+
+static sqlite3_vfs devsym_vfs = {
+ 2, /* iVersion */
+ sizeof(devsym_file), /* szOsFile */
+ DEVSYM_MAX_PATHNAME, /* mxPathname */
+ 0, /* pNext */
+ DEVSYM_VFS_NAME, /* zName */
+ 0, /* pAppData */
+ devsymOpen, /* xOpen */
+ devsymDelete, /* xDelete */
+ devsymAccess, /* xAccess */
+ devsymFullPathname, /* xFullPathname */
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ devsymDlOpen, /* xDlOpen */
+ devsymDlError, /* xDlError */
+ devsymDlSym, /* xDlSym */
+ devsymDlClose, /* xDlClose */
+#else
+ 0, /* xDlOpen */
+ 0, /* xDlError */
+ 0, /* xDlSym */
+ 0, /* xDlClose */
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
+ devsymRandomness, /* xRandomness */
+ devsymSleep, /* xSleep */
+ devsymCurrentTime, /* xCurrentTime */
+ 0, /* xGetLastError */
+ 0 /* xCurrentTimeInt64 */
+};
+
+static sqlite3_vfs writecrash_vfs = {
+ 2, /* iVersion */
+ sizeof(devsym_file), /* szOsFile */
+ DEVSYM_MAX_PATHNAME, /* mxPathname */
+ 0, /* pNext */
+ WRITECRASH_NAME, /* zName */
+ 0, /* pAppData */
+ writecrashOpen, /* xOpen */
+ devsymDelete, /* xDelete */
+ devsymAccess, /* xAccess */
+ devsymFullPathname, /* xFullPathname */
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ devsymDlOpen, /* xDlOpen */
+ devsymDlError, /* xDlError */
+ devsymDlSym, /* xDlSym */
+ devsymDlClose, /* xDlClose */
+#else
+ 0, /* xDlOpen */
+ 0, /* xDlError */
+ 0, /* xDlSym */
+ 0, /* xDlClose */
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
+ devsymRandomness, /* xRandomness */
+ devsymSleep, /* xSleep */
+ devsymCurrentTime, /* xCurrentTime */
+ 0, /* xGetLastError */
+ 0 /* xCurrentTimeInt64 */
+};
+
/*
** This procedure registers the devsym vfs with SQLite. If the argument is
@@ -379,10 +483,13 @@ static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
** available function in this file.
*/
void devsym_register(int iDeviceChar, int iSectorSize){
+
if( g.pVfs==0 ){
g.pVfs = sqlite3_vfs_find(0);
devsym_vfs.szOsFile += g.pVfs->szOsFile;
+ writecrash_vfs.szOsFile += g.pVfs->szOsFile;
sqlite3_vfs_register(&devsym_vfs, 0);
+ sqlite3_vfs_register(&writecrash_vfs, 0);
}
if( iDeviceChar>=0 ){
g.iDeviceChar = iDeviceChar;
@@ -403,4 +510,15 @@ void devsym_unregister(){
g.iSectorSize = 0;
}
+void devsym_crash_on_write(int nWrite){
+ if( g.pVfs==0 ){
+ g.pVfs = sqlite3_vfs_find(0);
+ devsym_vfs.szOsFile += g.pVfs->szOsFile;
+ writecrash_vfs.szOsFile += g.pVfs->szOsFile;
+ sqlite3_vfs_register(&devsym_vfs, 0);
+ sqlite3_vfs_register(&writecrash_vfs, 0);
+ }
+ g.nWriteCrash = nWrite;
+}
+
#endif
diff --git a/third_party/sqlite/src/src/test_func.c b/third_party/sqlite/src/src/test_func.c
index c8d2873..30f4a32 100644
--- a/third_party/sqlite/src/src/test_func.c
+++ b/third_party/sqlite/src/src/test_func.c
@@ -792,6 +792,123 @@ abuse_err:
/*
+** SQLite user defined function to use with matchinfo() to calculate the
+** relevancy of an FTS match. The value returned is the relevancy score
+** (a real value greater than or equal to zero). A larger value indicates
+** a more relevant document.
+**
+** The overall relevancy returned is the sum of the relevancies of each
+** column value in the FTS table. The relevancy of a column value is the
+** sum of the following for each reportable phrase in the FTS query:
+**
+** (<hit count> / <global hit count>) * <column weight>
+**
+** where <hit count> is the number of instances of the phrase in the
+** column value of the current row and <global hit count> is the number
+** of instances of the phrase in the same column of all rows in the FTS
+** table. The <column weight> is a weighting factor assigned to each
+** column by the caller (see below).
+**
+** The first argument to this function must be the return value of the FTS
+** matchinfo() function. Following this must be one argument for each column
+** of the FTS table containing a numeric weight factor for the corresponding
+** column. Example:
+**
+** CREATE VIRTUAL TABLE documents USING fts3(title, content)
+**
+** The following query returns the docids of documents that match the full-text
+** query <query> sorted from most to least relevant. When calculating
+** relevance, query term instances in the 'title' column are given twice the
+** weighting of those in the 'content' column.
+**
+** SELECT docid FROM documents
+** WHERE documents MATCH <query>
+** ORDER BY rank(matchinfo(documents), 1.0, 0.5) DESC
+*/
+static void rankfunc(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
+ int *aMatchinfo; /* Return value of matchinfo() */
+ int nMatchinfo; /* Number of elements in aMatchinfo[] */
+ int nCol = 0; /* Number of columns in the table */
+ int nPhrase = 0; /* Number of phrases in the query */
+ int iPhrase; /* Current phrase */
+ double score = 0.0; /* Value to return */
+
+ assert( sizeof(int)==4 );
+
+ /* Check that the number of arguments passed to this function is correct.
+ ** If not, jump to wrong_number_args. Set aMatchinfo to point to the array
+ ** of unsigned integer values returned by FTS function matchinfo. Set
+ ** nPhrase to contain the number of reportable phrases in the users full-text
+ ** query, and nCol to the number of columns in the table. Then check that the
+ ** size of the matchinfo blob is as expected. Return an error if it is not.
+ */
+ if( nVal<1 ) goto wrong_number_args;
+ aMatchinfo = (int*)sqlite3_value_blob(apVal[0]);
+ nMatchinfo = sqlite3_value_bytes(apVal[0]) / sizeof(int);
+ if( nMatchinfo>=2 ){
+ nPhrase = aMatchinfo[0];
+ nCol = aMatchinfo[1];
+ }
+ if( nMatchinfo!=(2+3*nCol*nPhrase) ){
+ sqlite3_result_error(pCtx,
+ "invalid matchinfo blob passed to function rank()", -1);
+ return;
+ }
+ if( nVal!=(1+nCol) ) goto wrong_number_args;
+
+ /* Iterate through each phrase in the users query. */
+ for(iPhrase=0; iPhrase<nPhrase; iPhrase++){
+ int iCol; /* Current column */
+
+ /* Now iterate through each column in the users query. For each column,
+ ** increment the relevancy score by:
+ **
+ ** (<hit count> / <global hit count>) * <column weight>
+ **
+ ** aPhraseinfo[] points to the start of the data for phrase iPhrase. So
+ ** the hit count and global hit counts for each column are found in
+ ** aPhraseinfo[iCol*3] and aPhraseinfo[iCol*3+1], respectively.
+ */
+ int *aPhraseinfo = &aMatchinfo[2 + iPhrase*nCol*3];
+ for(iCol=0; iCol<nCol; iCol++){
+ int nHitCount = aPhraseinfo[3*iCol];
+ int nGlobalHitCount = aPhraseinfo[3*iCol+1];
+ double weight = sqlite3_value_double(apVal[iCol+1]);
+ if( nHitCount>0 ){
+ score += ((double)nHitCount / (double)nGlobalHitCount) * weight;
+ }
+ }
+ }
+
+ sqlite3_result_double(pCtx, score);
+ return;
+
+ /* Jump here if the wrong number of arguments are passed to this function */
+wrong_number_args:
+ sqlite3_result_error(pCtx, "wrong number of arguments to function rank()", -1);
+}
+
+static int SQLITE_TCLAPI install_fts3_rank_function(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
+ sqlite3 *db;
+
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB");
+ return TCL_ERROR;
+ }
+
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ sqlite3_create_function(db, "rank", -1, SQLITE_UTF8, 0, rankfunc, 0, 0);
+ return TCL_OK;
+}
+
+
+/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest_func_Init(Tcl_Interp *interp){
@@ -801,6 +918,7 @@ int Sqlitetest_func_Init(Tcl_Interp *interp){
} aObjCmd[] = {
{ "autoinstall_test_functions", autoinstall_test_funcs },
{ "abuse_create_function", abuse_create_function },
+ { "install_fts3_rank_function", install_fts3_rank_function },
};
int i;
extern int Md5_Register(sqlite3 *, char **, const sqlite3_api_routines *);
diff --git a/third_party/sqlite/src/src/test_malloc.c b/third_party/sqlite/src/src/test_malloc.c
index 9283b9a..54a61df 100644
--- a/third_party/sqlite/src/src/test_malloc.c
+++ b/third_party/sqlite/src/src/test_malloc.c
@@ -888,46 +888,6 @@ static int SQLITE_TCLAPI test_memdebug_log(
}
/*
-** Usage: sqlite3_config_scratch SIZE N
-**
-** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
-** The buffer is static and is of limited size. N might be
-** adjusted downward as needed to accommodate the requested size.
-** The revised value of N is returned.
-**
-** A negative SIZE causes the buffer pointer to be NULL.
-*/
-static int SQLITE_TCLAPI test_config_scratch(
- void * clientData,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]
-){
- int sz, N, rc;
- Tcl_Obj *pResult;
- static char *buf = 0;
- if( objc!=3 ){
- Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
- return TCL_ERROR;
- }
- if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
- if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
- free(buf);
- if( sz<0 ){
- buf = 0;
- rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, (void*)0, 0, 0);
- }else{
- buf = malloc( sz*N + 1 );
- rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
- }
- pResult = Tcl_NewObj();
- Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
- Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
- Tcl_SetObjResult(interp, pResult);
- return TCL_OK;
-}
-
-/*
** Usage: sqlite3_config_pagecache SIZE N
**
** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
@@ -1538,7 +1498,6 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
{ "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 },
{ "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
{ "sqlite3_memdebug_log", test_memdebug_log ,0 },
- { "sqlite3_config_scratch", test_config_scratch ,0 },
{ "sqlite3_config_pagecache", test_config_pagecache ,0 },
{ "sqlite3_config_alt_pcache", test_alt_pcache ,0 },
{ "sqlite3_status", test_status ,0 },
diff --git a/third_party/sqlite/src/src/test_md5.c b/third_party/sqlite/src/src/test_md5.c
new file mode 100644
index 0000000..b670026
--- /dev/null
+++ b/third_party/sqlite/src/src/test_md5.c
@@ -0,0 +1,450 @@
+/*
+** 2017-10-13
+**
+** 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 code to implement an MD5 extension to TCL.
+*/
+#include "sqlite3.h"
+#include <stdlib.h>
+#include <string.h>
+#include "sqlite3.h"
+#if defined(INCLUDE_SQLITE_TCL_H)
+# include "sqlite_tcl.h"
+#else
+# include "tcl.h"
+# ifndef SQLITE_TCLAPI
+# define SQLITE_TCLAPI
+# endif
+#endif
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/*
+ * If compiled on a machine that doesn't have a 32-bit integer,
+ * you just set "uint32" to the appropriate datatype for an
+ * unsigned 32-bit integer. For example:
+ *
+ * cc -Duint32='unsigned long' md5.c
+ *
+ */
+#ifndef uint32
+# define uint32 unsigned int
+#endif
+
+struct MD5Context {
+ int isInit;
+ uint32 buf[4];
+ uint32 bits[2];
+ unsigned char in[64];
+};
+typedef struct MD5Context MD5Context;
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse (unsigned char *buf, unsigned longs){
+ uint32 t;
+ do {
+ t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
+ ((unsigned)buf[1]<<8 | buf[0]);
+ *(uint32 *)buf = t;
+ buf += 4;
+ } while (--longs);
+}
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(uint32 buf[4], const uint32 in[16]){
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+static void MD5Init(MD5Context *ctx){
+ ctx->isInit = 1;
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static
+void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if ( t ) {
+ unsigned char *p = (unsigned char *)ctx->in + t;
+
+ t = 64-t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+static void MD5Final(unsigned char digest[16], MD5Context *ctx){
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count-8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ memcpy(ctx->in + 14*4, ctx->bits, 8);
+
+ MD5Transform(ctx->buf, (uint32 *)ctx->in);
+ byteReverse((unsigned char *)ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+}
+
+/*
+** Convert a 128-bit MD5 digest into a 32-digit base-16 number.
+*/
+static void MD5DigestToBase16(unsigned char *digest, char *zBuf){
+ static char const zEncode[] = "0123456789abcdef";
+ int i, j;
+
+ for(j=i=0; i<16; i++){
+ int a = digest[i];
+ zBuf[j++] = zEncode[(a>>4)&0xf];
+ zBuf[j++] = zEncode[a & 0xf];
+ }
+ zBuf[j] = 0;
+}
+
+
+/*
+** Convert a 128-bit MD5 digest into sequency of eight 5-digit integers
+** each representing 16 bits of the digest and separated from each
+** other by a "-" character.
+*/
+static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
+ int i, j;
+ unsigned int x;
+ for(i=j=0; i<16; i+=2){
+ x = digest[i]*256 + digest[i+1];
+ if( i>0 ) zDigest[j++] = '-';
+ sqlite3_snprintf(50-j, &zDigest[j], "%05u", x);
+ j += 5;
+ }
+ zDigest[j] = 0;
+}
+
+/*
+** A TCL command for md5. The argument is the text to be hashed. The
+** Result is the hash in base64.
+*/
+static int SQLITE_TCLAPI md5_cmd(
+ void*cd,
+ Tcl_Interp *interp,
+ int argc,
+ const char **argv
+){
+ MD5Context ctx;
+ unsigned char digest[16];
+ char zBuf[50];
+ void (*converter)(unsigned char*, char*);
+
+ if( argc!=2 ){
+ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+ " TEXT\"", (char*)0);
+ return TCL_ERROR;
+ }
+ MD5Init(&ctx);
+ MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1]));
+ MD5Final(digest, &ctx);
+ converter = (void(*)(unsigned char*,char*))cd;
+ converter(digest, zBuf);
+ Tcl_AppendResult(interp, zBuf, (char*)0);
+ return TCL_OK;
+}
+
+/*
+** A TCL command to take the md5 hash of a file. The argument is the
+** name of the file.
+*/
+static int SQLITE_TCLAPI md5file_cmd(
+ void*cd,
+ Tcl_Interp *interp,
+ int argc,
+ const char **argv
+){
+ FILE *in;
+ int ofst;
+ int amt;
+ MD5Context ctx;
+ void (*converter)(unsigned char*, char*);
+ unsigned char digest[16];
+ char zBuf[10240];
+
+ if( argc!=2 && argc!=4 ){
+ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+ " FILENAME [OFFSET AMT]\"", (char*)0);
+ return TCL_ERROR;
+ }
+ if( argc==4 ){
+ ofst = atoi(argv[2]);
+ amt = atoi(argv[3]);
+ }else{
+ ofst = 0;
+ amt = 2147483647;
+ }
+ in = fopen(argv[1],"rb");
+ if( in==0 ){
+ Tcl_AppendResult(interp,"unable to open file \"", argv[1],
+ "\" for reading", (char*)0);
+ return TCL_ERROR;
+ }
+ fseek(in, ofst, SEEK_SET);
+ MD5Init(&ctx);
+ while( amt>0 ){
+ int n;
+ n = (int)fread(zBuf, 1, sizeof(zBuf)<=amt ? sizeof(zBuf) : amt, in);
+ if( n<=0 ) break;
+ MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
+ amt -= n;
+ }
+ fclose(in);
+ MD5Final(digest, &ctx);
+ converter = (void(*)(unsigned char*,char*))cd;
+ converter(digest, zBuf);
+ Tcl_AppendResult(interp, zBuf, (char*)0);
+ return TCL_OK;
+}
+
+/*
+** Register the four new TCL commands for generating MD5 checksums
+** with the TCL interpreter.
+*/
+int Md5_Init(Tcl_Interp *interp){
+ Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd,
+ MD5DigestToBase16, 0);
+ Tcl_CreateCommand(interp, "md5-10x8", (Tcl_CmdProc*)md5_cmd,
+ MD5DigestToBase10x8, 0);
+ Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd,
+ MD5DigestToBase16, 0);
+ Tcl_CreateCommand(interp, "md5file-10x8", (Tcl_CmdProc*)md5file_cmd,
+ MD5DigestToBase10x8, 0);
+ return TCL_OK;
+}
+
+/*
+** During testing, the special md5sum() aggregate function is available.
+** inside SQLite. The following routines implement that function.
+*/
+static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){
+ MD5Context *p;
+ int i;
+ if( argc<1 ) return;
+ p = sqlite3_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ if( !p->isInit ){
+ MD5Init(p);
+ }
+ for(i=0; i<argc; i++){
+ const char *zData = (char*)sqlite3_value_text(argv[i]);
+ if( zData ){
+ MD5Update(p, (unsigned char*)zData, (int)strlen(zData));
+ }
+ }
+}
+static void md5finalize(sqlite3_context *context){
+ MD5Context *p;
+ unsigned char digest[16];
+ char zBuf[33];
+ p = sqlite3_aggregate_context(context, sizeof(*p));
+ MD5Final(digest,p);
+ MD5DigestToBase16(digest, zBuf);
+ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+}
+int Md5_Register(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pThunk
+){
+ int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
+ md5step, md5finalize);
+ sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */
+ return rc;
+}
diff --git a/third_party/sqlite/src/src/test_tclsh.c b/third_party/sqlite/src/src/test_tclsh.c
new file mode 100644
index 0000000..976f7cb
--- /dev/null
+++ b/third_party/sqlite/src/src/test_tclsh.c
@@ -0,0 +1,198 @@
+/*
+** 2017-10-13
+**
+** 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 extensions to the the "tclsqlite.c" module used for
+** testing. Basically, all of the other "test_*.c" modules are linked
+** into the enhanced tclsh used for testing (and named "testfixture" or
+** "testfixture.exe") using logic encoded by this file.
+**
+** The code in this file used to be found in tclsqlite3.c, contained within
+** #if SQLITE_TEST ... #endif. It is factored out into this separate module
+** in an effort to keep the tclsqlite.c file pure.
+*/
+#include "sqlite3.h"
+#if defined(INCLUDE_SQLITE_TCL_H)
+# include "sqlite_tcl.h"
+#else
+# include "tcl.h"
+# ifndef SQLITE_TCLAPI
+# define SQLITE_TCLAPI
+# endif
+#endif
+
+/* Needed for the setrlimit() system call on unix */
+#if defined(unix)
+#include <sys/resource.h>
+#endif
+
+/* Forward declaration */
+static int SQLITE_TCLAPI load_testfixture_extensions(
+ ClientData cd,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+);
+
+/*
+** This routine is the primary export of this file.
+**
+** Configure the interpreter passed as the first argument to have access
+** to the commands and linked variables that make up:
+**
+** * the [sqlite3] extension itself,
+**
+** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
+**
+** * If SQLITE_TEST is set, the various test interfaces used by the Tcl
+** test suite.
+*/
+const char *sqlite3TestInit(Tcl_Interp *interp){
+ extern int Sqlite3_Init(Tcl_Interp*);
+ extern int Sqliteconfig_Init(Tcl_Interp*);
+ extern int Sqlitetest1_Init(Tcl_Interp*);
+ extern int Sqlitetest2_Init(Tcl_Interp*);
+ extern int Sqlitetest3_Init(Tcl_Interp*);
+ extern int Sqlitetest4_Init(Tcl_Interp*);
+ extern int Sqlitetest5_Init(Tcl_Interp*);
+ extern int Sqlitetest6_Init(Tcl_Interp*);
+ extern int Sqlitetest7_Init(Tcl_Interp*);
+ extern int Sqlitetest8_Init(Tcl_Interp*);
+ extern int Sqlitetest9_Init(Tcl_Interp*);
+ extern int Sqlitetestasync_Init(Tcl_Interp*);
+ extern int Sqlitetest_autoext_Init(Tcl_Interp*);
+ extern int Sqlitetest_blob_Init(Tcl_Interp*);
+ extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
+ extern int Sqlitetest_func_Init(Tcl_Interp*);
+ extern int Sqlitetest_hexio_Init(Tcl_Interp*);
+ extern int Sqlitetest_init_Init(Tcl_Interp*);
+ extern int Sqlitetest_malloc_Init(Tcl_Interp*);
+ extern int Sqlitetest_mutex_Init(Tcl_Interp*);
+ extern int Sqlitetestschema_Init(Tcl_Interp*);
+ extern int Sqlitetestsse_Init(Tcl_Interp*);
+ extern int Sqlitetesttclvar_Init(Tcl_Interp*);
+ extern int Sqlitetestfs_Init(Tcl_Interp*);
+ extern int SqlitetestThread_Init(Tcl_Interp*);
+ extern int SqlitetestOnefile_Init();
+ extern int SqlitetestOsinst_Init(Tcl_Interp*);
+ extern int Sqlitetestbackup_Init(Tcl_Interp*);
+ extern int Sqlitetestintarray_Init(Tcl_Interp*);
+ extern int Sqlitetestvfs_Init(Tcl_Interp *);
+ extern int Sqlitetestrtree_Init(Tcl_Interp*);
+ extern int Sqlitequota_Init(Tcl_Interp*);
+ extern int Sqlitemultiplex_Init(Tcl_Interp*);
+ extern int SqliteSuperlock_Init(Tcl_Interp*);
+ extern int SqlitetestSyscall_Init(Tcl_Interp*);
+#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
+ extern int TestSession_Init(Tcl_Interp*);
+#endif
+ extern int Md5_Init(Tcl_Interp*);
+ extern int Fts5tcl_Init(Tcl_Interp *);
+ extern int SqliteRbu_Init(Tcl_Interp*);
+ extern int Sqlitetesttcl_Init(Tcl_Interp*);
+#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
+ extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
+#endif
+#ifdef SQLITE_ENABLE_ZIPVFS
+ extern int Zipvfs_Init(Tcl_Interp*);
+#endif
+ Tcl_CmdInfo cmdInfo;
+
+ /* Since the primary use case for this binary is testing of SQLite,
+ ** be sure to generate core files if we crash */
+#if defined(unix)
+ { struct rlimit x;
+ getrlimit(RLIMIT_CORE, &x);
+ x.rlim_cur = x.rlim_max;
+ setrlimit(RLIMIT_CORE, &x);
+ }
+#endif /* unix */
+
+ if( Tcl_GetCommandInfo(interp, "sqlite3", &cmdInfo)==0 ){
+ Sqlite3_Init(interp);
+ }
+#ifdef SQLITE_ENABLE_ZIPVFS
+ Zipvfs_Init(interp);
+#endif
+ Md5_Init(interp);
+ Sqliteconfig_Init(interp);
+ Sqlitetest1_Init(interp);
+ Sqlitetest2_Init(interp);
+ Sqlitetest3_Init(interp);
+ Sqlitetest4_Init(interp);
+ Sqlitetest5_Init(interp);
+ Sqlitetest6_Init(interp);
+ Sqlitetest7_Init(interp);
+ Sqlitetest8_Init(interp);
+ Sqlitetest9_Init(interp);
+ Sqlitetestasync_Init(interp);
+ Sqlitetest_autoext_Init(interp);
+ Sqlitetest_blob_Init(interp);
+ Sqlitetest_demovfs_Init(interp);
+ Sqlitetest_func_Init(interp);
+ Sqlitetest_hexio_Init(interp);
+ Sqlitetest_init_Init(interp);
+ Sqlitetest_malloc_Init(interp);
+ Sqlitetest_mutex_Init(interp);
+ Sqlitetestschema_Init(interp);
+ Sqlitetesttclvar_Init(interp);
+ Sqlitetestfs_Init(interp);
+ SqlitetestThread_Init(interp);
+ SqlitetestOnefile_Init();
+ SqlitetestOsinst_Init(interp);
+ Sqlitetestbackup_Init(interp);
+ Sqlitetestintarray_Init(interp);
+ Sqlitetestvfs_Init(interp);
+ Sqlitetestrtree_Init(interp);
+ Sqlitequota_Init(interp);
+ Sqlitemultiplex_Init(interp);
+ SqliteSuperlock_Init(interp);
+ SqlitetestSyscall_Init(interp);
+#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
+ TestSession_Init(interp);
+#endif
+ Fts5tcl_Init(interp);
+ SqliteRbu_Init(interp);
+ Sqlitetesttcl_Init(interp);
+
+#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
+ Sqlitetestfts3_Init(interp);
+#endif
+
+ Tcl_CreateObjCommand(
+ interp, "load_testfixture_extensions", load_testfixture_extensions,0,0
+ );
+ return 0;
+}
+
+/* tclcmd: load_testfixture_extensions
+*/
+static int SQLITE_TCLAPI load_testfixture_extensions(
+ ClientData cd,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+
+ Tcl_Interp *slave;
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "SLAVE");
+ return TCL_ERROR;
+ }
+
+ slave = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
+ if( !slave ){
+ return TCL_ERROR;
+ }
+
+ (void)sqlite3TestInit(slave);
+ return TCL_OK;
+}
diff --git a/third_party/sqlite/src/src/test_tclvar.c b/third_party/sqlite/src/src/test_tclvar.c
index bef8ca9..c656c57 100644
--- a/third_party/sqlite/src/src/test_tclvar.c
+++ b/third_party/sqlite/src/src/test_tclvar.c
@@ -15,6 +15,25 @@
**
** The emphasis of this file is a virtual table that provides
** access to TCL variables.
+**
+** The TCLVAR eponymous virtual table has a schema like this:
+**
+** CREATE TABLE tclvar(
+** name TEXT, -- base name of the variable: "x" in "$x(y)"
+** arrayname TEXT, -- array index name: "y" in "$x(y)"
+** value TEXT, -- the value of the variable
+** fullname TEXT, -- the full name of the variable
+** PRIMARY KEY(fullname)
+** ) WITHOUT ROWID;
+**
+** DELETE, INSERT, and UPDATE operations use the "fullname" field to
+** determine the variable to be modified. Changing "value" to NULL
+** deletes the variable.
+**
+** For SELECT operations, the "name" and "arrayname" fields will always
+** match the "fullname" field. For DELETE, INSERT, and UPDATE, the
+** "name" and "arrayname" fields are ignored and the variable is modified
+** according to "fullname" and "value" only.
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
@@ -67,7 +86,12 @@ static int tclvarConnect(
){
tclvar_vtab *pVtab;
static const char zSchema[] =
- "CREATE TABLE whatever(name TEXT, arrayname TEXT, value TEXT)";
+ "CREATE TABLE x("
+ " name TEXT," /* Base name */
+ " arrayname TEXT," /* Array index */
+ " value TEXT," /* Value */
+ " fullname TEXT PRIMARY KEY" /* base(index) name */
+ ") WITHOUT ROWID";
pVtab = sqlite3MallocZero( sizeof(*pVtab) );
if( pVtab==0 ) return SQLITE_NOMEM;
*ppVtab = &pVtab->base;
@@ -251,6 +275,16 @@ static int tclvarColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
sqlite3_result_text(ctx, Tcl_GetString(pVal), -1, SQLITE_TRANSIENT);
break;
}
+ case 3: {
+ char *z3;
+ if( p2 ){
+ z3 = sqlite3_mprintf("%s(%s)", z1, z2);
+ sqlite3_result_text(ctx, z3, -1, sqlite3_free);
+ }else{
+ sqlite3_result_text(ctx, z1, -1, SQLITE_TRANSIENT);
+ }
+ break;
+ }
}
return SQLITE_OK;
}
@@ -377,6 +411,58 @@ static int tclvarBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
}
/*
+** Invoked for any UPDATE, INSERT, or DELETE against a tclvar table
+*/
+static int tclvarUpdate(
+ sqlite3_vtab *tab,
+ int argc,
+ sqlite3_value **argv,
+ sqlite_int64 *pRowid
+){
+ tclvar_vtab *pTab = (tclvar_vtab*)tab;
+ if( argc==1 ){
+ /* A DELETE operation. The variable to be deleted is stored in argv[0] */
+ const char *zVar = (const char*)sqlite3_value_text(argv[0]);
+ Tcl_UnsetVar(pTab->interp, zVar, TCL_GLOBAL_ONLY);
+ return SQLITE_OK;
+ }
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
+ /* An INSERT operation */
+ const char *zValue = (const char*)sqlite3_value_text(argv[4]);
+ const char *zName;
+ if( sqlite3_value_type(argv[5])!=SQLITE_TEXT ){
+ tab->zErrMsg = sqlite3_mprintf("the 'fullname' column must be TEXT");
+ return SQLITE_ERROR;
+ }
+ zName = (const char*)sqlite3_value_text(argv[5]);
+ if( zValue ){
+ Tcl_SetVar(pTab->interp, zName, zValue, TCL_GLOBAL_ONLY);
+ }else{
+ Tcl_UnsetVar(pTab->interp, zName, TCL_GLOBAL_ONLY);
+ }
+ return SQLITE_OK;
+ }
+ if( sqlite3_value_type(argv[0])==SQLITE_TEXT
+ && sqlite3_value_type(argv[1])==SQLITE_TEXT
+ ){
+ /* An UPDATE operation */
+ const char *zOldName = (const char*)sqlite3_value_text(argv[0]);
+ const char *zNewName = (const char*)sqlite3_value_text(argv[1]);
+ const char *zValue = (const char*)sqlite3_value_text(argv[4]);
+
+ if( strcmp(zOldName, zNewName)!=0 || zValue==0 ){
+ Tcl_UnsetVar(pTab->interp, zOldName, TCL_GLOBAL_ONLY);
+ }
+ if( zValue!=0 ){
+ Tcl_SetVar(pTab->interp, zNewName, zValue, TCL_GLOBAL_ONLY);
+ }
+ return SQLITE_OK;
+ }
+ tab->zErrMsg = sqlite3_mprintf("prohibited TCL variable change");
+ return SQLITE_ERROR;
+}
+
+/*
** A virtual table module that provides read-only access to a
** Tcl global variable namespace.
*/
@@ -394,7 +480,7 @@ static sqlite3_module tclvarModule = {
tclvarEof, /* xEof - check for end of scan */
tclvarColumn, /* xColumn - read data */
tclvarRowid, /* xRowid - read data */
- 0, /* xUpdate */
+ tclvarUpdate, /* xUpdate */
0, /* xBegin */
0, /* xSync */
0, /* xCommit */
diff --git a/third_party/sqlite/src/src/trigger.c b/third_party/sqlite/src/src/trigger.c
index fed6304..57fbc8e 100644
--- a/third_party/sqlite/src/src/trigger.c
+++ b/third_party/sqlite/src/src/trigger.c
@@ -585,7 +585,7 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
*pp = (*pp)->pNext;
}
sqlite3DeleteTrigger(db, pTrigger);
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
}
diff --git a/third_party/sqlite/src/src/update.c b/third_party/sqlite/src/src/update.c
index 0d3225d..ec8cbb5 100644
--- a/third_party/sqlite/src/src/update.c
+++ b/third_party/sqlite/src/src/update.c
@@ -803,12 +803,6 @@ static void updateVirtualTable(
if( pWInfo==0 ) return;
/* Populate the argument registers. */
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
- if( pRowid ){
- sqlite3ExprCode(pParse, pRowid, regArg+1);
- }else{
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
- }
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
@@ -816,6 +810,23 @@ static void updateVirtualTable(
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
}
}
+ 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{
+ 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);
+ }
bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
diff --git a/third_party/sqlite/src/src/util.c b/third_party/sqlite/src/src/util.c
index 941d26e..da4a772 100644
--- a/third_party/sqlite/src/src/util.c
+++ b/third_party/sqlite/src/src/util.c
@@ -491,7 +491,11 @@ do_atof_calc:
if( esign<0 ){
result = 0.0*s;
}else{
+#ifdef INFINITY
+ result = INFINITY*s;
+#else
result = 1e308*1e308*s; /* Infinity */
+#endif
}
}
}else{
@@ -553,16 +557,12 @@ static int compare2pow63(const char *zNum, int incr){
** Convert zNum to a 64-bit signed integer. zNum must be decimal. This
** routine does *not* accept hexadecimal notation.
**
-** If the zNum value is representable as a 64-bit twos-complement
-** integer, then write that value into *pNum and return 0.
-**
-** If zNum is exactly 9223372036854775808, return 2. This special
-** case is broken out because while 9223372036854775808 cannot be a
-** signed 64-bit integer, its negative -9223372036854775808 can be.
+** Returns:
**
-** If zNum is too big for a 64-bit integer and is not
-** 9223372036854775808 or if zNum contains any non-numeric text,
-** then return 1.
+** 0 Successful transformation. Fits in a 64-bit signed integer.
+** 1 Excess text after the integer value
+** 2 Integer too large for a 64-bit signed integer or is malformed
+** 3 Special case of 9223372036854775808
**
** length is the number of bytes in the string (bytes, not characters).
** The string is not necessarily zero-terminated. The encoding is
@@ -575,6 +575,7 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
int i;
int c = 0;
int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
+ int rc; /* Baseline return code */
const char *zStart;
const char *zEnd = zNum + length;
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
@@ -614,31 +615,35 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
testcase( i==20 );
if( &zNum[i]<zEnd /* Extra bytes at the end */
|| (i==0 && zStart==zNum) /* No digits */
- || i>19*incr /* Too many digits */
|| nonNum /* UTF16 with high-order bytes non-zero */
){
+ rc = 1;
+ }else{
+ rc = 0;
+ }
+ if( i>19*incr ){ /* Too many digits */
/* zNum is empty or contains non-numeric text or is longer
** than 19 digits (thus guaranteeing that it is too large) */
- return 1;
+ return 2;
}else if( i<19*incr ){
/* Less than 19 digits, so we know that it fits in 64 bits */
assert( u<=LARGEST_INT64 );
- return 0;
+ return rc;
}else{
/* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
c = compare2pow63(zNum, incr);
if( c<0 ){
/* zNum is less than 9223372036854775808 so it fits */
assert( u<=LARGEST_INT64 );
- return 0;
+ return rc;
}else if( c>0 ){
/* zNum is greater than 9223372036854775808 so it overflows */
- return 1;
+ return 2;
}else{
/* zNum is exactly 9223372036854775808. Fits if negative. The
** special case 2 overflow if positive */
assert( u-1==LARGEST_INT64 );
- return neg ? 0 : 2;
+ return neg ? rc : 3;
}
}
}
@@ -651,8 +656,9 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
** Returns:
**
** 0 Successful transformation. Fits in a 64-bit signed integer.
-** 1 Integer too large for a 64-bit signed integer or is malformed
-** 2 Special case of 9223372036854775808
+** 1 Excess text after the integer value
+** 2 Integer too large for a 64-bit signed integer or is malformed
+** 3 Special case of 9223372036854775808
*/
int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
#ifndef SQLITE_OMIT_HEX_INTEGER
@@ -666,7 +672,7 @@ int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
u = u*16 + sqlite3HexToInt(z[k]);
}
memcpy(pOut, &u, 8);
- return (z[k]==0 && k-i<=16) ? 0 : 1;
+ return (z[k]==0 && k-i<=16) ? 0 : 2;
}else
#endif /* SQLITE_OMIT_HEX_INTEGER */
{
@@ -1276,7 +1282,7 @@ int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
** overflow, leave *pA unchanged and return 1.
*/
int sqlite3AddInt64(i64 *pA, i64 iB){
-#if GCC_VERSION>=5004000
+#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
return __builtin_add_overflow(*pA, iB, pA);
#else
i64 iA = *pA;
@@ -1296,7 +1302,7 @@ int sqlite3AddInt64(i64 *pA, i64 iB){
#endif
}
int sqlite3SubInt64(i64 *pA, i64 iB){
-#if GCC_VERSION>=5004000
+#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
return __builtin_sub_overflow(*pA, iB, pA);
#else
testcase( iB==SMALLEST_INT64+1 );
@@ -1311,7 +1317,7 @@ int sqlite3SubInt64(i64 *pA, i64 iB){
#endif
}
int sqlite3MulInt64(i64 *pA, i64 iB){
-#if GCC_VERSION>=5004000
+#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
return __builtin_mul_overflow(*pA, iB, pA);
#else
i64 iA = *pA;
@@ -1413,8 +1419,14 @@ LogEst sqlite3LogEst(u64 x){
if( x<2 ) return 0;
while( x<8 ){ y -= 10; x <<= 1; }
}else{
+#if GCC_VERSION>=5004000
+ int i = 60 - __builtin_clzll(x);
+ y += i*10;
+ x >>= i;
+#else
while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/
while( x>15 ){ y += 10; x >>= 1; }
+#endif
}
return a[x&7] + y - 10;
}
diff --git a/third_party/sqlite/src/src/vacuum.c b/third_party/sqlite/src/src/vacuum.c
index 2480a6d..42e247f 100644
--- a/third_party/sqlite/src/src/vacuum.c
+++ b/third_party/sqlite/src/src/vacuum.c
@@ -130,7 +130,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
int rc = SQLITE_OK; /* Return code from service routines */
Btree *pMain; /* The database being vacuumed */
Btree *pTemp; /* The temporary database we vacuum into */
- int saved_flags; /* Saved value of the db->flags */
+ u16 saved_mDbFlags; /* Saved value of db->mDbFlags */
+ u32 saved_flags; /* Saved value of db->flags */
int saved_nChange; /* Saved value of db->nChange */
int saved_nTotalChange; /* Saved value of db->nTotalChange */
u8 saved_mTrace; /* Saved trace settings */
@@ -153,11 +154,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
** restored before returning. Then set the writable-schema flag, and
** disable CHECK and foreign key constraints. */
saved_flags = db->flags;
+ saved_mDbFlags = db->mDbFlags;
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
saved_mTrace = db->mTrace;
- db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks
- | SQLITE_PreferBuiltin | SQLITE_Vacuum);
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
+ db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows);
db->mTrace = 0;
@@ -268,8 +270,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
"WHERE type='table'AND coalesce(rootpage,1)>0",
zDbMain
);
- assert( (db->flags & SQLITE_Vacuum)!=0 );
- db->flags &= ~SQLITE_Vacuum;
+ assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
+ db->mDbFlags &= ~DBFLAG_Vacuum;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Copy the triggers, views, and virtual tables from the main database
@@ -337,6 +339,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
end_of_vacuum:
/* Restore the original value of db->flags */
db->init.iDb = 0;
+ db->mDbFlags = saved_mDbFlags;
db->flags = saved_flags;
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
diff --git a/third_party/sqlite/src/src/vdbe.c b/third_party/sqlite/src/src/vdbe.c
index 22f8682..3524959 100644
--- a/third_party/sqlite/src/src/vdbe.c
+++ b/third_party/sqlite/src/src/vdbe.c
@@ -354,7 +354,7 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){
return 0;
}
- if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
+ if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==0 ){
return MEM_Int;
}
return MEM_Real;
@@ -1955,13 +1955,23 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
}
compare_op:
- switch( pOp->opcode ){
- case OP_Eq: res2 = res==0; break;
- case OP_Ne: res2 = res; break;
- case OP_Lt: res2 = res<0; break;
- case OP_Le: res2 = res<=0; break;
- case OP_Gt: res2 = res>0; break;
- default: res2 = res>=0; break;
+ /* 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
+ ** operator actually is. The next block of code depends on the fact
+ ** that the 6 comparison operators are consecutive integers in this
+ ** 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];
+ }else if( res==0 ){
+ static const unsigned char aEQb[] = { 0, 1, 0, 1, 0, 1 };
+ res2 = aEQb[pOp->opcode - OP_Ne];
+ }else{
+ static const unsigned char aGTb[] = { 1, 0, 1, 0, 0, 1 };
+ res2 = aGTb[pOp->opcode - OP_Ne];
}
/* Undo any changes made by applyAffinity() to the input registers. */
@@ -1973,7 +1983,6 @@ compare_op:
if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
iCompare = res;
- res2 = res2!=0; /* For this path res2 must be exactly 0 or 1 */
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
@@ -2104,7 +2113,7 @@ case OP_Compare: {
assert( memIsValid(&aMem[p2+idx]) );
REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
- assert( i<pKeyInfo->nField );
+ assert( i<pKeyInfo->nKeyField );
pColl = pKeyInfo->aColl[i];
bRev = pKeyInfo->aSortOrder[i];
iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
@@ -2377,9 +2386,7 @@ case OP_Column: {
const u8 *zData; /* Part of the record being decoded */
const u8 *zHdr; /* Next unparsed byte of the header */
const u8 *zEndHdr; /* Pointer to first byte after the header */
- u32 offset; /* Offset into the data */
u64 offset64; /* 64-bit offset */
- u32 avail; /* Number of bytes of available data */
u32 t; /* A type code from the record header */
Mem *pReg; /* PseudoTable input register */
@@ -2406,11 +2413,13 @@ case OP_Column: {
if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/
if( pC->nullRow ){
if( pC->eCurType==CURTYPE_PSEUDO ){
- assert( pC->uc.pseudoTableReg>0 );
- pReg = &aMem[pC->uc.pseudoTableReg];
+ /* 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 = avail = pReg->n;
+ pC->payloadSize = pC->szRow = pReg->n;
pC->aRow = (u8*)pReg->z;
}else{
sqlite3VdbeMemSetNull(pDest);
@@ -2422,23 +2431,19 @@ case OP_Column: {
assert( pCrsr );
assert( sqlite3BtreeCursorIsValid(pCrsr) );
pC->payloadSize = sqlite3BtreePayloadSize(pCrsr);
- pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &avail);
- assert( avail<=65536 ); /* Maximum page size is 64KiB */
- if( pC->payloadSize <= (u32)avail ){
- pC->szRow = pC->payloadSize;
- }else if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ 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;
- }else{
- pC->szRow = avail;
}
}
pC->cacheStatus = p->cacheCtr;
- pC->iHdrOffset = getVarint32(pC->aRow, offset);
+ pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]);
pC->nHdrParsed = 0;
- aOffset[0] = offset;
- if( avail<offset ){ /*OPTIMIZATION-IF-FALSE*/
+ 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
** the complete header, then set it to zero, forcing the header to be
@@ -2455,17 +2460,26 @@ case OP_Column: {
** 3-byte type for each of the maximum of 32768 columns plus three
** extra bytes for the header length itself. 32768*3 + 3 = 98307.
*/
- if( offset > 98307 || offset > pC->payloadSize ){
- rc = SQLITE_CORRUPT_BKPT;
- goto abort_due_to_error;
+ if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){
+ goto op_column_corrupt;
}
- }else if( offset>0 ){ /*OPTIMIZATION-IF-TRUE*/
- /* The following goto is an optimization. It can be omitted and
- ** everything will still work. But OP_Column is measurably faster
- ** by skipping the subsequent conditional, which is always true.
+ }else{
+ /* This is an optimization. By skipping over the first few tests
+ ** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a
+ ** measurable performance gain.
+ **
+ ** This branch is taken even if aOffset[0]==0. Such a record is never
+ ** generated by SQLite, and could be considered corruption, but we
+ ** accept it for historical reasons. When aOffset[0]==0, the code this
+ ** branch jumps to reads past the end of the record, but never more
+ ** than a few bytes. Even if the record occurs at the end of the page
+ ** content area, the "page header" comes after the page content and so
+ ** this overread is harmless. Similar overreads can occur for a corrupt
+ ** database file.
*/
zData = pC->aRow;
assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */
+ testcase( aOffset[0]==0 );
goto op_column_read_header;
}
}
@@ -2494,6 +2508,7 @@ case OP_Column: {
offset64 = aOffset[i];
zHdr = zData + pC->iHdrOffset;
zEndHdr = zData + aOffset[0];
+ testcase( zHdr>=zEndHdr );
do{
if( (t = zHdr[0])<0x80 ){
zHdr++;
@@ -2514,9 +2529,13 @@ case OP_Column: {
if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize))
|| (offset64 > pC->payloadSize)
){
- if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
- rc = SQLITE_CORRUPT_BKPT;
- goto abort_due_to_error;
+ if( aOffset[0]==0 ){
+ i = 0;
+ zHdr = zEndHdr;
+ }else{
+ if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
+ goto op_column_corrupt;
+ }
}
pC->nHdrParsed = i;
@@ -2610,6 +2629,15 @@ op_column_out:
UPDATE_MAX_BLOBSIZE(pDest);
REGISTER_TRACE(pOp->p3, pDest);
break;
+
+op_column_corrupt:
+ if( aOp[0].p3>0 ){
+ pOp = &aOp[aOp[0].p3-1];
+ break;
+ }else{
+ rc = SQLITE_CORRUPT_BKPT;
+ goto abort_due_to_error;
+ }
}
/* Opcode: Affinity P1 P2 * P4 *
@@ -2950,7 +2978,7 @@ case OP_Savepoint: {
int isSchemaChange;
iSavepoint = db->nSavepoint - iSavepoint - 1;
if( p1==SAVEPOINT_ROLLBACK ){
- isSchemaChange = (db->flags & SQLITE_InternChanges)!=0;
+ isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0;
for(ii=0; ii<db->nDb; ii++){
rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,
SQLITE_ABORT_ROLLBACK,
@@ -2969,7 +2997,7 @@ case OP_Savepoint: {
if( isSchemaChange ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
- db->flags = (db->flags | SQLITE_InternChanges);
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
}
@@ -3249,7 +3277,7 @@ case OP_SetCookie: {
if( pOp->p2==BTREE_SCHEMA_VERSION ){
/* When the schema cookie changes, record the new cookie internally */
pDb->pSchema->schema_cookie = pOp->p3;
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}else if( pOp->p2==BTREE_FILE_FORMAT ){
/* Record changes in the file format */
pDb->pSchema->file_format = pOp->p3;
@@ -3388,7 +3416,7 @@ case OP_OpenWrite:
assert( (pIn2->flags & MEM_Int)!=0 );
sqlite3VdbeMemIntegerify(pIn2);
p2 = (int)pIn2->u.i;
- /* The p2 value always comes from a prior OP_CreateTable opcode and
+ /* The p2 value always comes from a prior OP_CreateBtree opcode and
** that opcode will always set the p2 value to 2 or more or else fail.
** If there were a failure, the prepared statement would have halted
** before reaching this instruction. */
@@ -3398,7 +3426,7 @@ case OP_OpenWrite:
pKeyInfo = pOp->p4.pKeyInfo;
assert( pKeyInfo->enc==ENC(db) );
assert( pKeyInfo->db==db );
- nField = pKeyInfo->nField+pKeyInfo->nXField;
+ nField = pKeyInfo->nAllField;
}else if( pOp->p4type==P4_INT32 ){
nField = pOp->p4.i;
}
@@ -3609,8 +3637,13 @@ case OP_OpenPseudo: {
pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
- pCx->uc.pseudoTableReg = pOp->p2;
+ pCx->seekResult = pOp->p2;
pCx->isTable = 1;
+ /* Give this pseudo-cursor a fake BtCursor pointer so that pCx
+ ** can be safely passed to sqlite3VdbeCursorMoveto(). This avoids a test
+ ** for pCx->eCurType==CURTYPE_BTREE inside of sqlite3VdbeCursorMoveto()
+ ** which is a performance optimization */
+ pCx->uc.pCursor = sqlite3BtreeFakeValidCursor();
assert( pOp->p5==0 );
break;
}
@@ -4402,14 +4435,9 @@ case OP_InsertInt: {
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
- if( pData->flags & MEM_Null ){
- x.pData = 0;
- x.nData = 0;
- }else{
- assert( pData->flags & (MEM_Blob|MEM_Str) );
- x.pData = pData->z;
- x.nData = pData->n;
- }
+ assert( pData->flags & (MEM_Blob|MEM_Str) );
+ x.pData = pData->z;
+ x.nData = pData->n;
seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0);
if( pData->flags & MEM_Zero ){
x.nZero = pData->u.nZero;
@@ -4776,7 +4804,17 @@ case OP_NullRow: {
break;
}
-/* Opcode: Last P1 P2 P3 * *
+/* Opcode: SeekEnd P1 * * * *
+**
+** Position cursor P1 at the end of the btree for the purpose of
+** appending a new entry onto the btree.
+**
+** It is assumed that the cursor is used only for appending and so
+** if the cursor is valid, then the cursor must already be pointing
+** at the end of the btree and so no changes are made to
+** the cursor.
+*/
+/* Opcode: Last P1 P2 * * *
**
** 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.
@@ -4787,14 +4825,8 @@ case OP_NullRow: {
** This opcode leaves the cursor configured to move in reverse order,
** from the end toward the beginning. In other words, the cursor is
** configured to use Prev, not Next.
-**
-** If P3 is -1, then the cursor is positioned at the end of the btree
-** for the purpose of appending a new entry onto the btree. In that
-** case P2 must be 0. It is assumed that the cursor is used only for
-** appending and so if the cursor is valid, then the cursor must already
-** be pointing at the end of the btree and so no changes are made to
-** the cursor.
*/
+case OP_SeekEnd:
case OP_Last: { /* jump */
VdbeCursor *pC;
BtCursor *pCrsr;
@@ -4807,22 +4839,24 @@ case OP_Last: { /* jump */
pCrsr = pC->uc.pCursor;
res = 0;
assert( pCrsr!=0 );
- pC->seekResult = pOp->p3;
#ifdef SQLITE_DEBUG
- pC->seekOp = OP_Last;
+ pC->seekOp = pOp->opcode;
#endif
- if( pOp->p3==0 || !sqlite3BtreeCursorIsValidNN(pCrsr) ){
- rc = sqlite3BtreeLast(pCrsr, &res);
- pC->nullRow = (u8)res;
- pC->deferredMoveto = 0;
- pC->cacheStatus = CACHE_STALE;
- if( rc ) goto abort_due_to_error;
- if( pOp->p2>0 ){
- VdbeBranchTaken(res!=0,2);
- if( res ) goto jump_to_p2;
- }
- }else{
+ if( pOp->opcode==OP_SeekEnd ){
assert( pOp->p2==0 );
+ pC->seekResult = -1;
+ if( sqlite3BtreeCursorIsValidNN(pCrsr) ){
+ break;
+ }
+ }
+ rc = sqlite3BtreeLast(pCrsr, &res);
+ pC->nullRow = (u8)res;
+ pC->deferredMoveto = 0;
+ pC->cacheStatus = CACHE_STALE;
+ if( rc ) goto abort_due_to_error;
+ if( pOp->p2>0 ){
+ VdbeBranchTaken(res!=0,2);
+ if( res ) goto jump_to_p2;
}
break;
}
@@ -5451,50 +5485,28 @@ case OP_ResetSorter: {
break;
}
-/* Opcode: CreateTable P1 P2 * * *
-** Synopsis: r[P2]=root iDb=P1
-**
-** Allocate a new table in the main database file if P1==0 or in the
-** auxiliary database file if P1==1 or in an attached database if
-** P1>1. Write the root page number of the new table into
-** register P2
-**
-** The difference between a table and an index is this: A table must
-** have a 4-byte integer key and can have arbitrary data. An index
-** has an arbitrary key but no data.
-**
-** See also: CreateIndex
-*/
-/* Opcode: CreateIndex P1 P2 * * *
-** Synopsis: r[P2]=root iDb=P1
-**
-** Allocate a new index in the main database file if P1==0 or in the
-** auxiliary database file if P1==1 or in an attached database if
-** P1>1. Write the root page number of the new table into
-** register P2.
+/* Opcode: CreateBtree P1 P2 P3 * *
+** Synopsis: r[P2]=root iDb=P1 flags=P3
**
-** See documentation on OP_CreateTable for additional information.
+** Allocate a new b-tree in the main database file if P1==0 or in the
+** TEMP database file if P1==1 or in an attached database if
+** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table
+** it must be 2 (BTREE_BLOBKEY) for a index or WITHOUT ROWID table.
+** The root page number of the new b-tree is stored in register P2.
*/
-case OP_CreateIndex: /* out2 */
-case OP_CreateTable: { /* out2 */
+case OP_CreateBtree: { /* out2 */
int pgno;
- int flags;
Db *pDb;
pOut = out2Prerelease(p, pOp);
pgno = 0;
+ assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p1) );
assert( p->readOnly==0 );
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
- if( pOp->opcode==OP_CreateTable ){
- /* flags = BTREE_INTKEY; */
- flags = BTREE_INTKEY;
- }else{
- flags = BTREE_BLOBKEY;
- }
- rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
+ rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, pOp->p3);
if( rc ) goto abort_due_to_error;
pOut->u.i = pgno;
break;
@@ -7005,7 +7017,7 @@ case OP_Function: {
}
-/* Opcode: Init P1 P2 * P4 *
+/* Opcode: Init P1 P2 P3 P4 *
** Synopsis: Start at P2
**
** Programs contain a single instance of this opcode as the very first
@@ -7019,6 +7031,9 @@ case OP_Function: {
**
** Increment the value of P1 so that OP_Once opcodes will jump the
** first time they are evaluated for this run.
+**
+** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT
+** error is encountered.
*/
case OP_Init: { /* jump */
char *zTrace;
diff --git a/third_party/sqlite/src/src/vdbeInt.h b/third_party/sqlite/src/src/vdbeInt.h
index c550e6d..63a33a2 100644
--- a/third_party/sqlite/src/src/vdbeInt.h
+++ b/third_party/sqlite/src/src/vdbeInt.h
@@ -96,18 +96,18 @@ struct VdbeCursor {
u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
int seekResult; /* Result of previous sqlite3BtreeMoveto() or 0
** if there have been no prior seeks on the cursor. */
- /* NB: seekResult does not distinguish between "no seeks have ever occurred
- ** on this cursor" and "the most recent seek was an exact match". */
+ /* seekResult does not distinguish between "no seeks have ever occurred
+ ** on this cursor" and "the most recent seek was an exact match".
+ ** For CURTYPE_PSEUDO, seekResult is the register holding the record */
/* When a new VdbeCursor is allocated, only the fields above are zeroed.
** The fields that follow are uninitialized, and must be individually
** initialized prior to first use. */
VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
union {
- BtCursor *pCursor; /* CURTYPE_BTREE. Btree cursor */
- sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */
- int pseudoTableReg; /* CURTYPE_PSEUDO. Reg holding content. */
- VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
+ BtCursor *pCursor; /* CURTYPE_BTREE or _PSEUDO. Btree cursor */
+ sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */
+ VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
} uc;
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
u32 iHdrOffset; /* Offset to next unparsed byte of the header */
diff --git a/third_party/sqlite/src/src/vdbeapi.c b/third_party/sqlite/src/src/vdbeapi.c
index 7450ce4..4338ce7 100644
--- a/third_party/sqlite/src/src/vdbeapi.c
+++ b/third_party/sqlite/src/src/vdbeapi.c
@@ -517,7 +517,7 @@ static int doWalCallbacks(sqlite3 *db){
sqlite3BtreeEnter(pBt);
nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
sqlite3BtreeLeave(pBt);
- if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
+ if( nEntry>0 && db->xWalCallback && rc==SQLITE_OK ){
rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry);
}
}
@@ -627,7 +627,7 @@ static int sqlite3Step(Vdbe *p){
if( rc!=SQLITE_ROW ) checkProfileCallback(db, p);
#endif
- if( rc==SQLITE_DONE ){
+ if( rc==SQLITE_DONE && db->autoCommit ){
assert( p->rc==SQLITE_OK );
p->rc = doWalCallbacks(db);
if( p->rc!=SQLITE_OK ){
@@ -671,7 +671,6 @@ end_of_step:
*/
int sqlite3_step(sqlite3_stmt *pStmt){
int rc = SQLITE_OK; /* Result from sqlite3Step() */
- int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */
Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */
int cnt = 0; /* Counter to prevent infinite loop of reprepares */
sqlite3 *db; /* The database connection */
@@ -685,32 +684,31 @@ int sqlite3_step(sqlite3_stmt *pStmt){
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
&& cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
int savedPc = v->pc;
- rc2 = rc = sqlite3Reprepare(v);
- if( rc!=SQLITE_OK) break;
+ 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
+ ** from the database handle into the statement and sets the statement
+ ** 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);
+ sqlite3DbFree(db, v->zErrMsg);
+ if( !db->mallocFailed ){
+ v->zErrMsg = sqlite3DbStrDup(db, zErr);
+ v->rc = rc = sqlite3ApiExit(db, rc);
+ } else {
+ v->zErrMsg = 0;
+ v->rc = rc = SQLITE_NOMEM_BKPT;
+ }
+ break;
+ }
sqlite3_reset(pStmt);
if( savedPc>=0 ) v->doingRerun = 1;
assert( v->expired==0 );
}
- if( rc2!=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
- ** from the database handle into the statement and sets the statement
- ** 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);
- sqlite3DbFree(db, v->zErrMsg);
- if( !db->mallocFailed ){
- v->zErrMsg = sqlite3DbStrDup(db, zErr);
- v->rc = rc2;
- } else {
- v->zErrMsg = 0;
- v->rc = rc = SQLITE_NOMEM_BKPT;
- }
- }
- rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -1708,7 +1706,7 @@ static UnpackedRecord *vdbeUnpackRecord(
pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
if( pRet ){
- memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1));
+ memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1));
sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
}
return pRet;
@@ -1781,7 +1779,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
*/
int sqlite3_preupdate_count(sqlite3 *db){
PreUpdate *p = db->pPreUpdate;
- return (p ? p->keyinfo.nField : 0);
+ return (p ? p->keyinfo.nKeyField : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
diff --git a/third_party/sqlite/src/src/vdbeaux.c b/third_party/sqlite/src/src/vdbeaux.c
index 8ae546f..e9eb0a8 100644
--- a/third_party/sqlite/src/src/vdbeaux.c
+++ b/third_party/sqlite/src/src/vdbeaux.c
@@ -33,10 +33,12 @@ Vdbe *sqlite3VdbeCreate(Parse *pParse){
db->pVdbe = p;
p->magic = VDBE_MAGIC_INIT;
p->pParse = pParse;
+ pParse->pVdbe = p;
assert( pParse->aLabel==0 );
assert( pParse->nLabel==0 );
assert( pParse->nOpAlloc==0 );
assert( pParse->szOpAlloc==0 );
+ sqlite3VdbeAddOp2(p, OP_Init, 0, 1);
return p;
}
@@ -490,7 +492,8 @@ static Op *opIterNext(VdbeOpIter *p){
** * OP_VUpdate
** * OP_VRename
** * OP_FkCounter with P2==0 (immediate foreign key constraint)
-** * OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...)
+** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine
+** (for CREATE TABLE AS SELECT ...)
**
** Then check that the value of Parse.mayAbort is true if an
** ABORT may be thrown, or false otherwise. Return true if it does
@@ -518,7 +521,7 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
hasAbort = 1;
break;
}
- if( opcode==OP_CreateTable ) hasCreateTable = 1;
+ if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1;
if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1;
#ifndef SQLITE_OMIT_FOREIGN_KEY
if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
@@ -597,6 +600,27 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
p->bIsReader = 1;
break;
}
+ case OP_Next:
+ case OP_NextIfOpen:
+ 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:
+ case OP_PrevIfOpen: {
+ 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 */
+ assert( pOp->p2>=0 );
+ break;
+ }
#ifndef SQLITE_OMIT_VIRTUALTABLE
case OP_VUpdate: {
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
@@ -608,27 +632,25 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
assert( pOp[-1].opcode==OP_Integer );
n = pOp[-1].p1;
if( n>nMaxArgs ) nMaxArgs = n;
- break;
+ /* Fall through into the default case */
}
#endif
- case OP_Next:
- case OP_NextIfOpen:
- case OP_SorterNext: {
- pOp->p4.xAdvance = sqlite3BtreeNext;
- pOp->p4type = P4_ADVANCE;
- break;
- }
- case OP_Prev:
- case OP_PrevIfOpen: {
- pOp->p4.xAdvance = sqlite3BtreePrevious;
- pOp->p4type = P4_ADVANCE;
+ default: {
+ if( pOp->p2<0 ){
+ /* The mkopcodeh.tcl script has so arranged things that the only
+ ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
+ ** have non-negative values for P2. */
+ assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
+ assert( ADDR(pOp->p2)<pParse->nLabel );
+ pOp->p2 = aLabel[ADDR(pOp->p2)];
+ }
break;
}
}
- if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){
- assert( ADDR(pOp->p2)<pParse->nLabel );
- pOp->p2 = aLabel[ADDR(pOp->p2)];
- }
+ /* The mkopcodeh.tcl script has so arranged things that the only
+ ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
+ ** have non-negative values for P2. */
+ assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
}
if( pOp==p->aOp ) break;
pOp--;
@@ -1301,8 +1323,8 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
int j;
KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
assert( pKeyInfo->aSortOrder!=0 );
- sqlite3XPrintf(&x, "k(%d", pKeyInfo->nField);
- for(j=0; j<pKeyInfo->nField; j++){
+ sqlite3XPrintf(&x, "k(%d", pKeyInfo->nKeyField);
+ for(j=0; j<pKeyInfo->nKeyField; j++){
CollSeq *pColl = pKeyInfo->aColl[j];
const char *zColl = pColl ? pColl->zName : "";
if( strcmp(zColl, "BINARY")==0 ) zColl = "B";
@@ -2139,27 +2161,6 @@ static void closeAllCursors(Vdbe *p){
}
/*
-** Clean up the VM after a single run.
-*/
-static void Cleanup(Vdbe *p){
- sqlite3 *db = p->db;
-
-#ifdef SQLITE_DEBUG
- /* Execute assert() statements to ensure that the Vdbe.apCsr[] and
- ** Vdbe.aMem[] arrays have already been cleaned up. */
- int i;
- 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;
-}
-
-/*
** Set the number of result columns that will be returned by this SQL
** statement. This is now set at compile time, rather than during
** execution of the vdbe program so that sqlite3_column_count() can
@@ -2867,6 +2868,10 @@ static void vdbeInvokeSqllog(Vdbe *v){
** VDBE_MAGIC_INIT.
*/
int sqlite3VdbeReset(Vdbe *p){
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+ int i;
+#endif
+
sqlite3 *db;
db = p->db;
@@ -2884,8 +2889,6 @@ int sqlite3VdbeReset(Vdbe *p){
if( p->pc>=0 ){
vdbeInvokeSqllog(p);
sqlite3VdbeTransferError(p);
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
if( p->runOnlyOnce ) p->expired = 1;
}else if( p->rc && p->expired ){
/* The expired flag was set on the VDBE before the first call
@@ -2893,13 +2896,21 @@ int sqlite3VdbeReset(Vdbe *p){
** called), set the database error in this case as well.
*/
sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
}
- /* Reclaim all memory used by the VDBE
+ /* Reset register contents and reclaim error message memory.
*/
- Cleanup(p);
+#ifdef SQLITE_DEBUG
+ /* 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;
/* Save profiling information from this VDBE run.
*/
@@ -2907,7 +2918,6 @@ int sqlite3VdbeReset(Vdbe *p){
{
FILE *out = fopen("vdbe_profile.out", "a");
if( out ){
- int i;
fprintf(out, "---- ");
for(i=0; i<p->nOp; i++){
fprintf(out, "%02x", p->aOp[i].opcode);
@@ -3120,19 +3130,18 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){
*/
int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
VdbeCursor *p = *pp;
- if( p->eCurType==CURTYPE_BTREE ){
- if( p->deferredMoveto ){
- int iMap;
- if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){
- *pp = p->pAltCursor;
- *piCol = iMap - 1;
- return SQLITE_OK;
- }
- return handleDeferredMoveto(p);
- }
- if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
- return handleMovedCursor(p);
+ 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 handleDeferredMoveto(p);
+ }
+ if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
+ return handleMovedCursor(p);
}
return SQLITE_OK;
}
@@ -3528,13 +3537,13 @@ UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
){
UnpackedRecord *p; /* Unpacked record to return */
int nByte; /* Number of bytes required for *p */
- nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1);
+ nByte = ROUND8(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))];
assert( pKeyInfo->aSortOrder!=0 );
p->pKeyInfo = pKeyInfo;
- p->nField = pKeyInfo->nField + 1;
+ p->nField = pKeyInfo->nKeyField + 1;
return p;
}
@@ -3574,7 +3583,7 @@ void sqlite3VdbeRecordUnpack(
pMem++;
if( (++u)>=p->nField ) break;
}
- assert( u<=pKeyInfo->nField + 1 );
+ assert( u<=pKeyInfo->nKeyField + 1 );
p->nField = u;
}
@@ -3623,9 +3632,9 @@ static int vdbeRecordCompareDebug(
idx1 = getVarint32(aKey1, szHdr1);
if( szHdr1>98307 ) return SQLITE_CORRUPT;
d1 = szHdr1;
- assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
+ assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB );
assert( pKeyInfo->aSortOrder!=0 );
- assert( pKeyInfo->nField>0 );
+ assert( pKeyInfo->nKeyField>0 );
assert( idx1<=szHdr1 || CORRUPT_DB );
do{
u32 serial_type1;
@@ -3687,12 +3696,12 @@ debugCompareEnd:
/*
** Count the number of fields (a.k.a. columns) in the record given by
** pKey,nKey. The verify that this count is less than or equal to the
-** limit given by pKeyInfo->nField + pKeyInfo->nXField.
+** limit given by pKeyInfo->nAllField.
**
** If this constraint is not satisfied, it means that the high-speed
** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will
** not work correctly. If this assert() ever fires, it probably means
-** that the KeyInfo.nField or KeyInfo.nXField values were computed
+** that the KeyInfo.nKeyField or KeyInfo.nAllField values were computed
** incorrectly.
*/
static void vdbeAssertFieldCountWithinLimits(
@@ -3713,7 +3722,7 @@ static void vdbeAssertFieldCountWithinLimits(
idx += getVarint32(aKey+idx, notUsed);
nField++;
}
- assert( nField <= pKeyInfo->nField+pKeyInfo->nXField );
+ assert( nField <= pKeyInfo->nAllField );
}
#else
# define vdbeAssertFieldCountWithinLimits(A,B,C)
@@ -4018,10 +4027,10 @@ int sqlite3VdbeRecordCompareWithSkip(
}
VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
- assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
+ assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField
|| CORRUPT_DB );
assert( pPKey2->pKeyInfo->aSortOrder!=0 );
- assert( pPKey2->pKeyInfo->nField>0 );
+ assert( pPKey2->pKeyInfo->nKeyField>0 );
assert( idx1<=szHdr1 || CORRUPT_DB );
do{
u32 serial_type;
@@ -4354,7 +4363,7 @@ RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
** The easiest way to enforce this limit is to consider only records with
** 13 fields or less. If the first field is an integer, the maximum legal
** header size is (12*5 + 1 + 1) bytes. */
- if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){
+ if( p->pKeyInfo->nAllField<=13 ){
int flags = p->aMem[0].flags;
if( p->pKeyInfo->aSortOrder[0] ){
p->r1 = 1;
@@ -4683,7 +4692,7 @@ void sqlite3VdbePreUpdateHook(
preupdate.iNewReg = iReg;
preupdate.keyinfo.db = db;
preupdate.keyinfo.enc = ENC(db);
- preupdate.keyinfo.nField = pTab->nCol;
+ preupdate.keyinfo.nKeyField = pTab->nCol;
preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder;
preupdate.iKey1 = iKey1;
preupdate.iKey2 = iKey2;
@@ -4693,8 +4702,8 @@ void sqlite3VdbePreUpdateHook(
db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
db->pPreUpdate = 0;
sqlite3DbFree(db, preupdate.aRecord);
- vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pUnpacked);
- vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pNewUnpacked);
+ vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
+ vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
if( preupdate.aNew ){
int i;
for(i=0; i<pCsr->nField; i++){
diff --git a/third_party/sqlite/src/src/vdbeblob.c b/third_party/sqlite/src/src/vdbeblob.c
index 96a98649..785efdc 100644
--- a/third_party/sqlite/src/src/vdbeblob.c
+++ b/third_party/sqlite/src/src/vdbeblob.c
@@ -63,11 +63,12 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
v->aMem[1].u.i = iRow;
/* If the statement has been run before (and is paused at the OP_ResultRow)
- ** then back it up to the point where it does the OP_SeekRowid. This could
+ ** then back it up to the point where it does the OP_NotExists. This could
** have been down with an extra OP_Goto, but simply setting the program
** counter is faster. */
- if( v->pc>3 ){
- v->pc = 3;
+ if( v->pc>4 ){
+ v->pc = 4;
+ assert( v->aOp[v->pc].opcode==OP_NotExists );
rc = sqlite3VdbeExec(v);
}else{
rc = sqlite3_step(p->pStmt);
@@ -129,8 +130,8 @@ int sqlite3_blob_open(
int rc = SQLITE_OK;
char *zErr = 0;
Table *pTab;
- Parse *pParse = 0;
Incrblob *pBlob = 0;
+ Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppBlob==0 ){
@@ -148,37 +149,34 @@ int sqlite3_blob_open(
sqlite3_mutex_enter(db->mutex);
pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
- if( !pBlob ) goto blob_open_out;
- pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
- if( !pParse ) goto blob_open_out;
-
do {
- memset(pParse, 0, sizeof(Parse));
- pParse->db = db;
+ memset(&sParse, 0, sizeof(Parse));
+ if( !pBlob ) goto blob_open_out;
+ sParse.db = db;
sqlite3DbFree(db, zErr);
zErr = 0;
sqlite3BtreeEnterAll(db);
- pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
+ pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
if( pTab && IsVirtual(pTab) ){
pTab = 0;
- sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);
+ sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable);
}
if( pTab && !HasRowid(pTab) ){
pTab = 0;
- sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable);
+ sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
}
#ifndef SQLITE_OMIT_VIEW
if( pTab && pTab->pSelect ){
pTab = 0;
- sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable);
+ sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
}
#endif
if( !pTab ){
- if( pParse->zErrMsg ){
+ if( sParse.zErrMsg ){
sqlite3DbFree(db, zErr);
- zErr = pParse->zErrMsg;
- pParse->zErrMsg = 0;
+ zErr = sParse.zErrMsg;
+ sParse.zErrMsg = 0;
}
rc = SQLITE_ERROR;
sqlite3BtreeLeaveAll(db);
@@ -242,7 +240,7 @@ int sqlite3_blob_open(
}
}
- pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
+ pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse);
assert( pBlob->pStmt || db->mallocFailed );
if( pBlob->pStmt ){
@@ -279,6 +277,7 @@ int sqlite3_blob_open(
pTab->pSchema->schema_cookie,
pTab->pSchema->iGeneration);
sqlite3VdbeChangeP5(v, 1);
+ assert( sqlite3VdbeCurrentAddr(v)==2 || db->mallocFailed );
aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
/* Make sure a mutex is held on the table to be accessed */
@@ -293,7 +292,7 @@ int sqlite3_blob_open(
aOp[0].p1 = iDb;
aOp[0].p2 = pTab->tnum;
aOp[0].p3 = wrFlag;
- sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
+ sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
}
if( db->mallocFailed==0 ){
#endif
@@ -315,10 +314,10 @@ int sqlite3_blob_open(
aOp[1].p4.i = pTab->nCol+1;
aOp[3].p2 = pTab->nCol;
- pParse->nVar = 0;
- pParse->nMem = 1;
- pParse->nTab = 1;
- sqlite3VdbeMakeReady(v, pParse);
+ sParse.nVar = 0;
+ sParse.nMem = 1;
+ sParse.nTab = 1;
+ sqlite3VdbeMakeReady(v, &sParse);
}
}
@@ -340,8 +339,7 @@ blob_open_out:
}
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
- sqlite3ParserReset(pParse);
- sqlite3StackFree(db, pParse);
+ sqlite3ParserReset(&sParse);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
diff --git a/third_party/sqlite/src/src/vdbemem.c b/third_party/sqlite/src/src/vdbemem.c
index 31dc301ea..ec6c14a 100644
--- a/third_party/sqlite/src/src/vdbemem.c
+++ b/third_party/sqlite/src/src/vdbemem.c
@@ -130,7 +130,7 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
assert( pMem->szMalloc==0
|| pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
if( n<32 ) n = 32;
- if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
+ if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
bPreserve = 0;
}else{
@@ -146,7 +146,8 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
}
- if( bPreserve && pMem->z && ALWAYS(pMem->z!=pMem->zMalloc) ){
+ if( bPreserve && pMem->z ){
+ assert( pMem->z!=pMem->zMalloc );
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( (pMem->flags&MEM_Dyn)!=0 ){
@@ -185,6 +186,20 @@ int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
}
/*
+** It is already known that pMem contains an unterminated string.
+** Add the zero terminator.
+*/
+static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
+ if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
+ return SQLITE_NOMEM_BKPT;
+ }
+ pMem->z[pMem->n] = 0;
+ pMem->z[pMem->n+1] = 0;
+ pMem->flags |= MEM_Term;
+ return SQLITE_OK;
+}
+
+/*
** Change pMem so that its MEM_Str or MEM_Blob value is stored in
** MEM.zMalloc, where it can be safely written.
**
@@ -196,12 +211,8 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
- if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
- return SQLITE_NOMEM_BKPT;
- }
- pMem->z[pMem->n] = 0;
- pMem->z[pMem->n+1] = 0;
- pMem->flags |= MEM_Term;
+ int rc = vdbeMemAddTerminator(pMem);
+ if( rc ) return rc;
}
}
pMem->flags &= ~MEM_Ephem;
@@ -241,20 +252,6 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){
#endif
/*
-** It is already known that pMem contains an unterminated string.
-** Add the zero terminator.
-*/
-static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
- if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
- return SQLITE_NOMEM_BKPT;
- }
- pMem->z[pMem->n] = 0;
- pMem->z[pMem->n+1] = 0;
- pMem->flags |= MEM_Term;
- return SQLITE_OK;
-}
-
-/*
** Make sure the given Mem is \u0000 terminated.
*/
int sqlite3VdbeMemNulTerminate(Mem *pMem){
@@ -572,14 +569,21 @@ int sqlite3VdbeMemRealify(Mem *pMem){
*/
int sqlite3VdbeMemNumerify(Mem *pMem){
if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
+ int rc;
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
+ rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc);
+ if( rc==0 ){
MemSetTypeFlag(pMem, MEM_Int);
}else{
- pMem->u.r = sqlite3VdbeRealValue(pMem);
- MemSetTypeFlag(pMem, MEM_Real);
- sqlite3VdbeIntegerAffinity(pMem);
+ i64 i = pMem->u.i;
+ sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
+ if( rc==1 && pMem->u.r==(double)i ){
+ pMem->u.i = i;
+ MemSetTypeFlag(pMem, MEM_Int);
+ }else{
+ MemSetTypeFlag(pMem, MEM_Real);
+ }
}
}
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
@@ -899,7 +903,7 @@ int sqlite3VdbeMemSetStr(
if( nByte<0 ){
assert( enc!=0 );
if( enc==SQLITE_UTF8 ){
- nByte = sqlite3Strlen30(z);
+ nByte = 0x7fffffff & (int)strlen(z);
if( nByte>iLimit ) nByte = iLimit+1;
}else{
for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
@@ -977,12 +981,11 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
){
int rc;
pMem->flags = MEM_Null;
- if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
+ if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){
rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z);
if( rc==SQLITE_OK ){
- pMem->z[amt] = 0;
- pMem->z[amt+1] = 0;
- pMem->flags = MEM_Blob|MEM_Term;
+ pMem->z[amt] = 0; /* Overrun area used when reading malformed records */
+ pMem->flags = MEM_Blob;
pMem->n = (int)amt;
}else{
sqlite3VdbeMemRelease(pMem);
@@ -1131,7 +1134,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
if( pRec ){
pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx);
if( pRec->pKeyInfo ){
- assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol );
+ assert( pRec->pKeyInfo->nAllField==nCol );
assert( pRec->pKeyInfo->enc==ENC(db) );
pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord)));
for(i=0; i<nCol; i++){
@@ -1667,7 +1670,7 @@ int sqlite3Stat4Column(
void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
if( pRec ){
int i;
- int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField;
+ int nCol = pRec->pKeyInfo->nAllField;
Mem *aMem = pRec->aMem;
sqlite3 *db = aMem[0].db;
for(i=0; i<nCol; i++){
diff --git a/third_party/sqlite/src/src/vdbesort.c b/third_party/sqlite/src/src/vdbesort.c
index 30be45a..9fd4303 100644
--- a/third_party/sqlite/src/src/vdbesort.c
+++ b/third_party/sqlite/src/src/vdbesort.c
@@ -823,7 +823,7 @@ static int vdbeSorterCompareText(
}
if( res==0 ){
- if( pTask->pSorter->pKeyInfo->nField>1 ){
+ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
res = vdbeSorterCompareTail(
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
);
@@ -892,7 +892,7 @@ static int vdbeSorterCompareInt(
}
if( res==0 ){
- if( pTask->pSorter->pKeyInfo->nField>1 ){
+ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
res = vdbeSorterCompareTail(
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
);
@@ -907,7 +907,7 @@ static int vdbeSorterCompareInt(
/*
** Initialize the temporary index cursor just opened as a sorter cursor.
**
-** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField)
+** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nKeyField)
** to determine the number of fields that should be compared from the
** records being sorted. However, if the value passed as argument nField
** is non-zero and the sorter is able to guarantee a stable sort, nField
@@ -960,7 +960,7 @@ int sqlite3VdbeSorterInit(
assert( pCsr->pKeyInfo && pCsr->pBtx==0 );
assert( pCsr->eCurType==CURTYPE_SORTER );
- szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
+ szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
@@ -972,8 +972,7 @@ int sqlite3VdbeSorterInit(
memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
pKeyInfo->db = 0;
if( nField && nWorker==0 ){
- pKeyInfo->nXField += (pKeyInfo->nField - nField);
- pKeyInfo->nField = nField;
+ pKeyInfo->nKeyField = nField;
}
pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
pSorter->nTask = nWorker + 1;
@@ -1001,11 +1000,9 @@ int sqlite3VdbeSorterInit(
mxCache = MIN(mxCache, SQLITE_MAX_PMASZ);
pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache);
- /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
- ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
- ** large heap allocations.
- */
- if( sqlite3GlobalConfig.pScratch==0 ){
+ /* Avoid large memory allocations if the application has requested
+ ** SQLITE_CONFIG_SMALL_MALLOC. */
+ if( sqlite3GlobalConfig.bSmallMalloc==0 ){
assert( pSorter->iMemory==0 );
pSorter->nMemory = pgsz;
pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz);
@@ -1013,7 +1010,7 @@ int sqlite3VdbeSorterInit(
}
}
- if( (pKeyInfo->nField+pKeyInfo->nXField)<13
+ if( pKeyInfo->nAllField<13
&& (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
){
pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
@@ -1328,7 +1325,7 @@ static int vdbeSortAllocUnpacked(SortSubtask *pTask){
if( pTask->pUnpacked==0 ){
pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo);
if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT;
- pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField;
+ pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nKeyField;
pTask->pUnpacked->errCode = 0;
}
return SQLITE_OK;
diff --git a/third_party/sqlite/src/src/vdbetrace.c b/third_party/sqlite/src/src/vdbetrace.c
index b565c5c..da3036a 100644
--- a/third_party/sqlite/src/src/vdbetrace.c
+++ b/third_party/sqlite/src/src/vdbetrace.c
@@ -82,7 +82,7 @@ char *sqlite3VdbeExpandSql(
Mem *pVar; /* Value of a host parameter */
StrAccum out; /* Accumulate the output here */
#ifndef SQLITE_OMIT_UTF16
- Mem utf8; /* Used to convert UTF16 parameters into UTF8 for display */
+ Mem utf8; /* Used to convert UTF16 into UTF8 for display */
#endif
char zBase[100]; /* Initial working space */
diff --git a/third_party/sqlite/src/src/vtab.c b/third_party/sqlite/src/src/vtab.c
index f2dc732..bdf20f1 100644
--- a/third_party/sqlite/src/src/vtab.c
+++ b/third_party/sqlite/src/src/vtab.c
@@ -42,8 +42,10 @@ Module *sqlite3VtabCreateModule(
){
Module *pMod;
int nName = sqlite3Strlen30(zName);
- pMod = (Module *)sqlite3DbMallocRawNN(db, sizeof(Module) + nName + 1);
- if( pMod ){
+ pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1);
+ if( pMod==0 ){
+ sqlite3OomFault(db);
+ }else{
Module *pDel;
char *zCopy = (char *)(&pMod[1]);
memcpy(zCopy, zName, nName+1);
@@ -518,13 +520,14 @@ static int vtabCallConstructor(
}
}
- zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
+ zModuleName = sqlite3DbStrDup(db, pTab->zName);
if( !zModuleName ){
return SQLITE_NOMEM_BKPT;
}
- pVTable = sqlite3DbMallocZero(db, sizeof(VTable));
+ pVTable = sqlite3MallocZero(sizeof(VTable));
if( !pVTable ){
+ sqlite3OomFault(db);
sqlite3DbFree(db, zModuleName);
return SQLITE_NOMEM_BKPT;
}
@@ -644,6 +647,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "%s", zErr);
+ pParse->rc = rc;
}
sqlite3DbFree(db, zErr);
}
@@ -733,10 +737,10 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
*/
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
VtabCtx *pCtx;
- Parse *pParse;
int rc = SQLITE_OK;
Table *pTab;
char *zErr = 0;
+ Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
@@ -753,55 +757,55 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
pTab = pCtx->pTab;
assert( IsVirtual(pTab) );
- pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
- if( pParse==0 ){
- rc = SQLITE_NOMEM_BKPT;
- }else{
- pParse->declareVtab = 1;
- pParse->db = db;
- pParse->nQueryLoop = 1;
-
- if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr)
- && pParse->pNewTable
- && !db->mallocFailed
- && !pParse->pNewTable->pSelect
- && !IsVirtual(pParse->pNewTable)
- ){
- if( !pTab->aCol ){
- Table *pNew = pParse->pNewTable;
- Index *pIdx;
- pTab->aCol = pNew->aCol;
- pTab->nCol = pNew->nCol;
- pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
- pNew->nCol = 0;
- pNew->aCol = 0;
- assert( pTab->pIndex==0 );
- if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){
- rc = SQLITE_ERROR;
- }
- pIdx = pNew->pIndex;
- if( pIdx ){
- assert( pIdx->pNext==0 );
- pTab->pIndex = pIdx;
- pNew->pIndex = 0;
- pIdx->pTable = pTab;
- }
+ memset(&sParse, 0, sizeof(sParse));
+ sParse.declareVtab = 1;
+ sParse.db = db;
+ sParse.nQueryLoop = 1;
+ if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
+ && sParse.pNewTable
+ && !db->mallocFailed
+ && !sParse.pNewTable->pSelect
+ && !IsVirtual(sParse.pNewTable)
+ ){
+ if( !pTab->aCol ){
+ Table *pNew = sParse.pNewTable;
+ Index *pIdx;
+ pTab->aCol = pNew->aCol;
+ pTab->nCol = pNew->nCol;
+ pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
+ pNew->nCol = 0;
+ pNew->aCol = 0;
+ assert( pTab->pIndex==0 );
+ assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 );
+ if( !HasRowid(pNew)
+ && pCtx->pVTable->pMod->pModule->xUpdate!=0
+ && sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1
+ ){
+ /* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0)
+ ** or else must have a single-column PRIMARY KEY */
+ rc = SQLITE_ERROR;
+ }
+ pIdx = pNew->pIndex;
+ if( pIdx ){
+ assert( pIdx->pNext==0 );
+ pTab->pIndex = pIdx;
+ pNew->pIndex = 0;
+ pIdx->pTable = pTab;
}
- pCtx->bDeclared = 1;
- }else{
- sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
- sqlite3DbFree(db, zErr);
- rc = SQLITE_ERROR;
}
- pParse->declareVtab = 0;
+ pCtx->bDeclared = 1;
+ }else{
+ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
+ sqlite3DbFree(db, zErr);
+ rc = SQLITE_ERROR;
+ }
+ sParse.declareVtab = 0;
- if( pParse->pVdbe ){
- sqlite3VdbeFinalize(pParse->pVdbe);
- }
- sqlite3DeleteTable(db, pParse->pNewTable);
- sqlite3ParserReset(pParse);
- sqlite3StackFree(db, pParse);
+ if( sParse.pVdbe ){
+ sqlite3VdbeFinalize(sParse.pVdbe);
}
+ sqlite3DeleteTable(db, sParse.pNewTable);
+ sqlite3ParserReset(&sParse);
assert( (rc&0xff)==rc );
rc = sqlite3ApiExit(db, rc);
diff --git a/third_party/sqlite/src/src/wal.c b/third_party/sqlite/src/src/wal.c
index 0a3bc37..a88be06 100644
--- a/third_party/sqlite/src/src/wal.c
+++ b/third_party/sqlite/src/src/wal.c
@@ -1798,9 +1798,7 @@ static int walCheckpoint(
pInfo->nBackfillAttempted = mxSafeFrame;
/* Sync the WAL to disk */
- if( sync_flags ){
- rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
- }
+ rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
/* If the database may grow as a result of this checkpoint, hint
** about the eventual size of the db file to the VFS layer.
@@ -1841,8 +1839,8 @@ static int walCheckpoint(
i64 szDb = pWal->hdr.nPage*(i64)szPage;
testcase( IS_BIG_INT(szDb) );
rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
- if( rc==SQLITE_OK && sync_flags ){
- rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags));
}
}
if( rc==SQLITE_OK ){
@@ -2948,8 +2946,8 @@ static int walWriteToLog(
iOffset += iFirstAmt;
iAmt -= iFirstAmt;
pContent = (void*)(iFirstAmt + (char*)pContent);
- assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
- rc = sqlite3OsSync(p->pFd, p->syncFlags & SQLITE_SYNC_MASK);
+ assert( WAL_SYNC_FLAGS(p->syncFlags)!=0 );
+ rc = sqlite3OsSync(p->pFd, WAL_SYNC_FLAGS(p->syncFlags));
if( iAmt==0 || rc ) return rc;
}
rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
@@ -3119,10 +3117,10 @@ int sqlite3WalFrames(
** an out-of-order write following a WAL restart could result in
** database corruption. See the ticket:
**
- ** http://localhost:591/sqlite/info/ff5be73dee
+ ** https://sqlite.org/src/info/ff5be73dee
*/
- if( pWal->syncHeader && sync_flags ){
- rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
+ if( pWal->syncHeader ){
+ rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
if( rc ) return rc;
}
}
@@ -3197,7 +3195,7 @@ int sqlite3WalFrames(
** sector boundary is synced; the part of the last frame that extends
** past the sector boundary is written after the sync.
*/
- if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
+ if( isCommit && WAL_SYNC_FLAGS(sync_flags)!=0 ){
int bSync = 1;
if( pWal->padToSectorBoundary ){
int sectorSize = sqlite3SectorSize(pWal->pWalFd);
@@ -3213,7 +3211,7 @@ int sqlite3WalFrames(
}
if( bSync ){
assert( rc==SQLITE_OK );
- rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
+ rc = sqlite3OsSync(w.pFd, WAL_SYNC_FLAGS(sync_flags));
}
}
diff --git a/third_party/sqlite/src/src/wal.h b/third_party/sqlite/src/src/wal.h
index df831b5..27b8272 100644
--- a/third_party/sqlite/src/src/wal.h
+++ b/third_party/sqlite/src/src/wal.h
@@ -19,11 +19,11 @@
#include "sqliteInt.h"
-/* Additional values that can be added to the sync_flags argument of
-** sqlite3WalFrames():
+/* Macros for extracting appropriate sync flags for either transaction
+** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)):
*/
-#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */
-#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */
+#define WAL_SYNC_FLAGS(X) ((X)&0x03)
+#define CKPT_SYNC_FLAGS(X) (((X)>>2)&0x03)
#ifdef SQLITE_OMIT_WAL
# define sqlite3WalOpen(x,y,z) 0
diff --git a/third_party/sqlite/src/src/walker.c b/third_party/sqlite/src/src/walker.c
index 99333d1..d21ac1a 100644
--- a/third_party/sqlite/src/src/walker.c
+++ b/third_party/sqlite/src/src/walker.c
@@ -40,18 +40,22 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
int rc;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
- rc = pWalker->xExprCallback(pWalker, pExpr);
- if( rc ) return rc & WRC_Abort;
- if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
- if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
- assert( pExpr->x.pList==0 || pExpr->pRight==0 );
- if( pExpr->pRight ){
- if( walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
- }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
- }else if( pExpr->x.pList ){
- if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
+ while(1){
+ rc = pWalker->xExprCallback(pWalker, pExpr);
+ if( rc ) return rc & WRC_Abort;
+ if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
+ if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
+ assert( pExpr->x.pList==0 || pExpr->pRight==0 );
+ if( pExpr->pRight ){
+ pExpr = pExpr->pRight;
+ continue;
+ }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
+ }else if( pExpr->x.pList ){
+ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
+ }
}
+ break;
}
return WRC_Continue;
}
diff --git a/third_party/sqlite/src/src/where.c b/third_party/sqlite/src/src/where.c
index 63f26b6..13f6100 100644
--- a/third_party/sqlite/src/src/where.c
+++ b/third_party/sqlite/src/src/where.c
@@ -403,8 +403,8 @@ static int findIndexCol(
&& p->iColumn==pIdx->aiColumn[iCol]
&& p->iTable==iBase
){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
- if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){
+ CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr);
+ if( 0==sqlite3StrICmp(pColl->zName, zColl) ){
return i;
}
}
@@ -868,7 +868,7 @@ static sqlite3_index_info *allocateIndexInfo(
testcase( pTerm->eOperator & WO_ISNULL );
testcase( pTerm->eOperator & WO_IS );
testcase( pTerm->eOperator & WO_ALL );
- if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
+ if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
assert( pTerm->u.leftColumn>=(-1) );
nTerm++;
@@ -916,7 +916,7 @@ static sqlite3_index_info *allocateIndexInfo(
pUsage;
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
- u8 op;
+ u16 op;
if( pTerm->leftCursor != pSrc->iCursor ) continue;
if( pTerm->prereqRight & mUnusable ) continue;
assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
@@ -924,34 +924,40 @@ static sqlite3_index_info *allocateIndexInfo(
testcase( pTerm->eOperator & WO_IS );
testcase( pTerm->eOperator & WO_ISNULL );
testcase( pTerm->eOperator & WO_ALL );
- if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
+ if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
assert( pTerm->u.leftColumn>=(-1) );
pIdxCons[j].iColumn = pTerm->u.leftColumn;
pIdxCons[j].iTermOffset = i;
- op = (u8)pTerm->eOperator & WO_ALL;
+ op = pTerm->eOperator & WO_ALL;
if( op==WO_IN ) op = WO_EQ;
- if( op==WO_MATCH ){
- op = pTerm->eMatchOp;
- }
- pIdxCons[j].op = op;
- /* The direct assignment in the previous line is possible only because
- ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
- ** following asserts verify this fact. */
- assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
- assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
- assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
- assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
- assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
- assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
- assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
-
- if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
- && sqlite3ExprIsVector(pTerm->pExpr->pRight)
- ){
- if( i<16 ) mNoOmit |= (1 << i);
- if( op==WO_LT ) pIdxCons[j].op = WO_LE;
- if( op==WO_GT ) pIdxCons[j].op = WO_GE;
+ if( op==WO_AUX ){
+ pIdxCons[j].op = pTerm->eMatchOp;
+ }else if( op & (WO_ISNULL|WO_IS) ){
+ if( op==WO_ISNULL ){
+ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL;
+ }else{
+ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS;
+ }
+ }else{
+ pIdxCons[j].op = (u8)op;
+ /* The direct assignment in the previous line is possible only because
+ ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
+ ** following asserts verify this fact. */
+ assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
+ assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
+ assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
+ assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
+ assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
+ 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)
+ ){
+ if( i<16 ) mNoOmit |= (1 << i);
+ if( op==WO_LT ) pIdxCons[j].op = WO_LE;
+ if( op==WO_GT ) pIdxCons[j].op = WO_GE;
+ }
}
j++;
@@ -1879,18 +1885,19 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
** Return TRUE if all of the following are true:
**
** (1) X has the same or lower cost that Y
-** (2) X is a proper subset of Y
-** (3) X skips at least as many columns as Y
-**
-** By "proper subset" we mean that X uses fewer WHERE clause terms
-** than Y and that every WHERE clause term used by X is also used
-** by 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
+** (5) If X is a covering index, than Y is too
**
+** 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
-** relationship is inverted and needs to be adjusted. The third rule
+** 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.
+** deserve a lower cost even if it is a proper subset of Y. Constraint (5)
+** was added because a covering index probably deserves to have a lower cost
+** than a non-covering index even if it is a proper subset.
*/
static int whereLoopCheaperProperSubset(
const WhereLoop *pX, /* First WhereLoop to compare */
@@ -1912,6 +1919,10 @@ 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
+ && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
+ return 0; /* Constraint (5) */
+ }
return 1; /* All conditions meet */
}
@@ -2663,7 +2674,7 @@ static int indexMightHelpWithOrderBy(
}else if( (aColExpr = pIndex->aColExpr)!=0 ){
for(jj=0; jj<pIndex->nKeyCol; jj++){
if( pIndex->aiColumn[jj]!=XN_EXPR ) continue;
- if( sqlite3ExprCompare(0, pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
+ if( sqlite3ExprCompareSkip(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
return 1;
}
}
@@ -3573,14 +3584,10 @@ static i8 wherePathSatisfiesOrderBy(
if( j>=pLoop->nLTerm ) continue;
}
if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){
- const char *z1, *z2;
- pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- z1 = pColl->zName;
- pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- z2 = pColl->zName;
- if( sqlite3StrICmp(z1, z2)!=0 ) continue;
+ if( sqlite3ExprCollSeqMatch(pWInfo->pParse,
+ pOrderBy->a[i].pExpr, pTerm->pExpr)==0 ){
+ continue;
+ }
testcase( pTerm->pExpr->op==TK_IS );
}
obSat |= MASKBIT(i);
@@ -3652,7 +3659,7 @@ static i8 wherePathSatisfiesOrderBy(
if( pIndex ){
iColumn = pIndex->aiColumn[j];
revIdx = pIndex->aSortOrder[j];
- if( iColumn==pIndex->pTable->iPKey ) iColumn = -1;
+ if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID;
}else{
iColumn = XN_ROWID;
revIdx = 0;
@@ -3679,19 +3686,18 @@ static i8 wherePathSatisfiesOrderBy(
testcase( wctrlFlags & WHERE_GROUPBY );
testcase( wctrlFlags & WHERE_DISTINCTBY );
if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
- if( iColumn>=(-1) ){
+ if( iColumn>=XN_ROWID ){
if( pOBExpr->op!=TK_COLUMN ) continue;
if( pOBExpr->iTable!=iCur ) continue;
if( pOBExpr->iColumn!=iColumn ) continue;
}else{
- if( sqlite3ExprCompare(0,
- pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){
+ Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr;
+ if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){
continue;
}
}
- if( iColumn>=0 ){
- pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
- if( !pColl ) pColl = db->pDfltColl;
+ if( iColumn!=XN_ROWID ){
+ pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
}
pLoop->u.btree.nIdxCol = j+1;
@@ -4328,6 +4334,7 @@ static int exprIsDeterministic(Expr *p){
memset(&w, 0, sizeof(w));
w.eCode = 1;
w.xExprCallback = exprNodeIsDeterministic;
+ w.xSelectCallback = sqlite3SelectWalkFail;
sqlite3WalkExpr(&w, p);
return w.eCode;
}
@@ -4537,36 +4544,37 @@ WhereInfo *sqlite3WhereBegin(
if( wctrlFlags & WHERE_WANT_DISTINCT ){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
- }
-
- /* Assign a bit from the bitmask to every term in the FROM clause.
- **
- ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
- **
- ** The rule of the previous sentence ensures thta if X is the bitmask for
- ** a table T, then X-1 is the bitmask for all other tables to the left of T.
- ** Knowing the bitmask for all tables to the left of a left join is
- ** important. Ticket #3015.
- **
- ** Note that bitmasks are created for all pTabList->nSrc tables in
- ** pTabList, not just the first nTabList tables. nTabList is normally
- ** equal to pTabList->nSrc but might be shortened to 1 if the
- ** WHERE_OR_SUBCLAUSE flag is set.
- */
- for(ii=0; ii<pTabList->nSrc; ii++){
- createMask(pMaskSet, pTabList->a[ii].iCursor);
- sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
- }
-#ifdef SQLITE_DEBUG
- {
- Bitmask mx = 0;
- for(ii=0; ii<pTabList->nSrc; ii++){
- Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
- assert( m>=mx );
- mx = m;
+ }else{
+ /* Assign a bit from the bitmask to every term in the FROM clause.
+ **
+ ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
+ **
+ ** The rule of the previous sentence ensures thta if X is the bitmask for
+ ** a table T, then X-1 is the bitmask for all other tables to the left of T.
+ ** Knowing the bitmask for all tables to the left of a left join is
+ ** important. Ticket #3015.
+ **
+ ** Note that bitmasks are created for all pTabList->nSrc tables in
+ ** pTabList, not just the first nTabList tables. nTabList is normally
+ ** equal to pTabList->nSrc but might be shortened to 1 if the
+ ** WHERE_OR_SUBCLAUSE flag is set.
+ */
+ ii = 0;
+ do{
+ createMask(pMaskSet, pTabList->a[ii].iCursor);
+ sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
+ }while( (++ii)<pTabList->nSrc );
+ #ifdef SQLITE_DEBUG
+ {
+ Bitmask mx = 0;
+ for(ii=0; ii<pTabList->nSrc; ii++){
+ Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
+ assert( m>=mx );
+ mx = m;
+ }
}
+ #endif
}
-#endif
/* Analyze all of the subexpressions. */
sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
@@ -4790,7 +4798,7 @@ WhereInfo *sqlite3WhereBegin(
Index *pIx = pLoop->u.btree.pIndex;
int iIndexCur;
int op = OP_OpenRead;
- /* iAuxArg is always set if to a positive value if ONEPASS is possible */
+ /* iAuxArg is always set to a positive value if ONEPASS is possible */
assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 );
if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx)
&& (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0
diff --git a/third_party/sqlite/src/src/whereInt.h b/third_party/sqlite/src/src/whereInt.h
index 909cbb0..03b74bb 100644
--- a/third_party/sqlite/src/src/whereInt.h
+++ b/third_party/sqlite/src/src/whereInt.h
@@ -515,7 +515,6 @@ void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
** WO_LE == SQLITE_INDEX_CONSTRAINT_LE
** WO_GT == SQLITE_INDEX_CONSTRAINT_GT
** WO_GE == SQLITE_INDEX_CONSTRAINT_GE
-** WO_MATCH == SQLITE_INDEX_CONSTRAINT_MATCH
*/
#define WO_IN 0x0001
#define WO_EQ 0x0002
@@ -523,7 +522,7 @@ void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
#define WO_LE (WO_EQ<<(TK_LE-TK_EQ))
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
-#define WO_MATCH 0x0040
+#define WO_AUX 0x0040 /* Op useful to virtual tables only */
#define WO_IS 0x0080
#define WO_ISNULL 0x0100
#define WO_OR 0x0200 /* Two or more OR-connected terms */
diff --git a/third_party/sqlite/src/src/wherecode.c b/third_party/sqlite/src/src/wherecode.c
index 7c16d0d..edb0c25 100644
--- a/third_party/sqlite/src/src/wherecode.c
+++ b/third_party/sqlite/src/src/wherecode.c
@@ -794,7 +794,7 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
pWalker->eCode = 1;
}else if( pExpr->op==TK_FUNCTION ){
int d1;
- char d2[3];
+ char d2[4];
if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){
pWalker->eCode = 1;
}
@@ -1017,7 +1017,7 @@ static void codeDeferredSeek(
*/
static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
assert( nReg>0 );
- if( sqlite3ExprIsVector(p) ){
+ if( p && sqlite3ExprIsVector(p) ){
#ifndef SQLITE_OMIT_SUBQUERY
if( (p->flags & EP_xIsSelect) ){
Vdbe *v = pParse->pVdbe;
@@ -1070,9 +1070,9 @@ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
}
/*
-** 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.
+** 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.
*/
static void whereIndexExprTrans(
Index *pIdx, /* The Index */
diff --git a/third_party/sqlite/src/src/whereexpr.c b/third_party/sqlite/src/src/whereexpr.c
index 3d53959..fa71539 100644
--- a/third_party/sqlite/src/src/whereexpr.c
+++ b/third_party/sqlite/src/src/whereexpr.c
@@ -194,12 +194,12 @@ static int isLikeOrGlob(
int *pisComplete, /* True if the only wildcard is % in the last character */
int *pnoCase /* True if uppercase is equivalent to lowercase */
){
- const char *z = 0; /* String on RHS of LIKE operator */
+ const u8 *z = 0; /* String on RHS of LIKE operator */
Expr *pRight, *pLeft; /* Right and left size of LIKE operator */
ExprList *pList; /* List of operands to the LIKE operator */
int c; /* One character in z[] */
int cnt; /* Number of non-wildcard prefix characters */
- char wc[3]; /* Wildcard characters */
+ char wc[4]; /* Wildcard characters */
sqlite3 *db = pParse->db; /* Database connection */
sqlite3_value *pVal = 0;
int op; /* Opcode of pRight */
@@ -221,12 +221,12 @@ static int isLikeOrGlob(
int iCol = pRight->iColumn;
pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB);
if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
- z = (char *)sqlite3_value_text(pVal);
+ z = sqlite3_value_text(pVal);
}
sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
}else if( op==TK_STRING ){
- z = pRight->u.zToken;
+ z = (u8*)pRight->u.zToken;
}
if( z ){
@@ -246,16 +246,42 @@ static int isLikeOrGlob(
return 0;
}
}
+
+ /* Count the number of prefix characters prior to the first wildcard */
cnt = 0;
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
cnt++;
+ if( c==wc[3] && z[cnt]!=0 ) cnt++;
}
+
+ /* The optimization is possible only if (1) the pattern does not begin
+ ** with a wildcard and if (2) the non-wildcard prefix does not end with
+ ** an (illegal 0xff) character. The second condition is necessary so
+ ** that we can increment the prefix key to find an upper bound for the
+ ** range search.
+ */
if( cnt!=0 && 255!=(u8)z[cnt-1] ){
Expr *pPrefix;
+
+ /* A "complete" match if the pattern ends with "*" or "%" */
*pisComplete = c==wc[0] && z[cnt+1]==0;
- pPrefix = sqlite3Expr(db, TK_STRING, z);
- if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
+
+ /* Get the pattern prefix. Remove all escapes from the prefix. */
+ pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
+ if( pPrefix ){
+ int iFrom, iTo;
+ char *zNew = pPrefix->u.zToken;
+ zNew[cnt] = 0;
+ for(iFrom=iTo=0; iFrom<cnt; iFrom++){
+ if( zNew[iFrom]==wc[3] ) iFrom++;
+ zNew[iTo++] = zNew[iFrom];
+ }
+ zNew[iTo] = 0;
+ }
*ppPrefix = pPrefix;
+
+ /* If the RHS pattern is a bound parameter, make arrangements to
+ ** reprepare the statement when that parameter is rebound */
if( op==TK_VARIABLE ){
Vdbe *v = pParse->pVdbe;
sqlite3VdbeSetVarmask(v, pRight->iColumn);
@@ -286,48 +312,84 @@ static int isLikeOrGlob(
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
-** Check to see if the given expression is of the form
+** Check to see if the pExpr expression is a form that needs to be passed
+** to the xBestIndex method of virtual tables. Forms of interest include:
**
-** column OP expr
+** Expression Virtual Table Operator
+** ----------------------- ---------------------------------
+** 1. column MATCH expr SQLITE_INDEX_CONSTRAINT_MATCH
+** 2. column GLOB expr SQLITE_INDEX_CONSTRAINT_GLOB
+** 3. column LIKE expr SQLITE_INDEX_CONSTRAINT_LIKE
+** 4. column REGEXP expr SQLITE_INDEX_CONSTRAINT_REGEXP
+** 5. column != expr SQLITE_INDEX_CONSTRAINT_NE
+** 6. expr != column SQLITE_INDEX_CONSTRAINT_NE
+** 7. column IS NOT expr SQLITE_INDEX_CONSTRAINT_ISNOT
+** 8. expr IS NOT column SQLITE_INDEX_CONSTRAINT_ISNOT
+** 9. column IS NOT NULL SQLITE_INDEX_CONSTRAINT_ISNOTNULL
**
-** where OP is one of MATCH, GLOB, LIKE or REGEXP and "column" is a
-** column of a virtual table.
+** 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
+** "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
+** is a match. The usual return is 1, but if the RHS is also a column
+** of virtual table in forms (5) or (7) then return 2.
**
-** If it is then return TRUE. If not, return FALSE.
+** If the expression matches none of the patterns above, return 0.
*/
-static int isMatchOfColumn(
+static int isAuxiliaryVtabOperator(
Expr *pExpr, /* Test this expression */
- unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */
+ unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */
+ Expr **ppLeft, /* Column expression to left of MATCH/op2 */
+ Expr **ppRight /* Expression to left of MATCH/op2 */
){
- static const struct Op2 {
- const char *zOp;
- unsigned char eOp2;
- } aOp[] = {
- { "match", SQLITE_INDEX_CONSTRAINT_MATCH },
- { "glob", SQLITE_INDEX_CONSTRAINT_GLOB },
- { "like", SQLITE_INDEX_CONSTRAINT_LIKE },
- { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP }
- };
- ExprList *pList;
- Expr *pCol; /* Column reference */
- int i;
+ if( pExpr->op==TK_FUNCTION ){
+ static const struct Op2 {
+ const char *zOp;
+ unsigned char eOp2;
+ } aOp[] = {
+ { "match", SQLITE_INDEX_CONSTRAINT_MATCH },
+ { "glob", SQLITE_INDEX_CONSTRAINT_GLOB },
+ { "like", SQLITE_INDEX_CONSTRAINT_LIKE },
+ { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP }
+ };
+ ExprList *pList;
+ Expr *pCol; /* Column reference */
+ int i;
- if( pExpr->op!=TK_FUNCTION ){
- return 0;
- }
- pList = pExpr->x.pList;
- if( pList==0 || pList->nExpr!=2 ){
- return 0;
- }
- pCol = pList->a[1].pExpr;
- if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){
- return 0;
- }
- for(i=0; i<ArraySize(aOp); i++){
- if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
- *peOp2 = aOp[i].eOp2;
- return 1;
+ pList = pExpr->x.pList;
+ if( pList==0 || pList->nExpr!=2 ){
+ return 0;
+ }
+ pCol = pList->a[1].pExpr;
+ if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){
+ return 0;
+ }
+ for(i=0; i<ArraySize(aOp); i++){
+ if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
+ *peOp2 = aOp[i].eOp2;
+ *ppRight = pList->a[0].pExpr;
+ *ppLeft = pCol;
+ return 1;
+ }
}
+ }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
+ int res = 0;
+ Expr *pLeft = pExpr->pLeft;
+ Expr *pRight = pExpr->pRight;
+ if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->pTab) ){
+ res++;
+ }
+ if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->pTab) ){
+ res++;
+ SWAP(Expr*, pLeft, pRight);
+ }
+ *ppLeft = pLeft;
+ *ppRight = pRight;
+ if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE;
+ if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT;
+ if( pExpr->op==TK_NOTNULL ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOTNULL;
+ return res;
}
return 0;
}
@@ -578,7 +640,7 @@ static void exprAnalyzeOrTerm(
for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
assert( pAndTerm->pExpr );
if( allowedOp(pAndTerm->pExpr->op)
- || pAndTerm->eOperator==WO_MATCH
+ || pAndTerm->eOperator==WO_AUX
){
b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor);
}
@@ -780,7 +842,6 @@ static void exprAnalyzeOrTerm(
static int termIsEquivalence(Parse *pParse, Expr *pExpr){
char aff1, aff2;
CollSeq *pColl;
- const char *zColl1, *zColl2;
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;
@@ -793,11 +854,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
}
pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
- pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
- zColl1 = pColl ? pColl->zName : 0;
- pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
- zColl2 = pColl ? pColl->zName : 0;
- return sqlite3_stricmp(zColl1, zColl2)==0;
+ return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
}
/*
@@ -1160,41 +1217,46 @@ static void exprAnalyze(
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
#ifndef SQLITE_OMIT_VIRTUALTABLE
- /* Add a WO_MATCH auxiliary term to the constraint set if the
- ** current expression is of the form: column MATCH expr.
+ /* 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 && isMatchOfColumn(pExpr, &eOp2) ){
- int idxNew;
+ if( pWC->op==TK_AND ){
Expr *pRight, *pLeft;
- WhereTerm *pNewTerm;
- Bitmask prereqColumn, prereqExpr;
-
- pRight = pExpr->x.pList->a[0].pExpr;
- pLeft = pExpr->x.pList->a[1].pExpr;
- 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);
+ int res = isAuxiliaryVtabOperator(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);
+ }
+ 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;
}
- 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_MATCH;
- 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 */
diff --git a/third_party/sqlite/src/test/analyze9.test b/third_party/sqlite/src/test/analyze9.test
index e3cf6d8..b0dc905 100644
--- a/third_party/sqlite/src/test/analyze9.test
+++ b/third_party/sqlite/src/test/analyze9.test
@@ -1052,8 +1052,11 @@ do_execsql_test 23.0 {
do_eqp_test 23.1 {
SELECT * FROM t4 WHERE
(e=1 AND b='xyz' AND c='zyx' AND a<'AEA') AND f<300
+ -- Formerly used index i41. But i41 is not a covering index whereas
+ -- the PRIMARY KEY is a covering index, and so as of 2017-10-15, the
+ -- PRIMARY KEY is preferred.
} {
- 0 0 0 {SEARCH TABLE t4 USING INDEX i41 (e=? AND c=? AND b=? AND a<?)}
+ 0 0 0 {SEARCH TABLE t4 USING PRIMARY KEY (c=? AND b=? AND a<?)}
}
do_eqp_test 23.2 {
SELECT * FROM t4 WHERE
diff --git a/third_party/sqlite/src/test/atomic.test b/third_party/sqlite/src/test/atomic.test
new file mode 100644
index 0000000..6ce6deb
--- /dev/null
+++ b/third_party/sqlite/src/test/atomic.test
@@ -0,0 +1,41 @@
+# 2015-11-07
+#
+# 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 regression tests for SQLite library. The
+# focus of this file is testing the WITH clause.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set ::testprefix atomic
+
+db close
+if {[atomic_batch_write test.db]==0} {
+ puts "No f2fs atomic-batch-write support. Skipping tests..."
+ finish_test
+ return
+}
+
+reset_db
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1(x, y);
+ BEGIN;
+ INSERT INTO t1 VALUES(1, 2);
+}
+
+do_test 1.1 { file exists test.db-journal } {0}
+
+do_execsql_test 1.2 {
+ COMMIT;
+}
+
+
+finish_test
diff --git a/third_party/sqlite/src/test/attach2.test b/third_party/sqlite/src/test/attach2.test
index a034b9c..c65a39f 100644
--- a/third_party/sqlite/src/test/attach2.test
+++ b/third_party/sqlite/src/test/attach2.test
@@ -374,23 +374,17 @@ do_test attach2-6.1 {
do_test attach2-6.2 {
catchsql {
ATTACH 'test3.db' as aux2;
+ DETACH aux2;
}
-} {1 {cannot ATTACH database within transaction}}
+} {0 {}}
-# EVIDENCE-OF: R-59740-55581 This statement will fail if SQLite is in
-# the middle of a transaction.
+# As of version 3.21.0: it is ok to DETACH from within a transaction
#
do_test attach2-6.3 {
catchsql {
DETACH aux;
}
-} {1 {cannot DETACH database within transaction}}
-do_test attach2-6.4 {
- execsql {
- COMMIT;
- DETACH aux;
- }
-} {}
+} {0 {}}
db close
diff --git a/third_party/sqlite/src/test/bestindex5.test b/third_party/sqlite/src/test/bestindex5.test
new file mode 100644
index 0000000..0f1a669
--- /dev/null
+++ b/third_party/sqlite/src/test/bestindex5.test
@@ -0,0 +1,250 @@
+# 2017 September 10
+#
+# 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.
+#
+#***********************************************************************
+# Test the virtual table interface. In particular the xBestIndex
+# method.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix bestindex4
+
+ifcapable !vtab {
+ finish_test
+ return
+}
+
+#-------------------------------------------------------------------------
+# Virtual table callback for a virtual table named $tbl.
+#
+proc vtab_cmd {method args} {
+
+ set binops(ne) !=
+ set binops(eq) =
+ set binops(isnot) "IS NOT"
+ set binops(is) "IS"
+
+ set unops(isnotnull) "IS NOT NULL"
+ set unops(isnull) "IS NULL"
+
+ set cols(0) a
+ set cols(1) b
+ set cols(2) c
+
+ switch -- $method {
+ xConnect {
+ return "CREATE TABLE t1(a, b, c)"
+ }
+
+ xBestIndex {
+ foreach {clist orderby mask} $args {}
+
+ set cost 1000000.0
+ set ret [list]
+ set str [list]
+
+ set v 0
+ for {set i 0} {$i < [llength $clist]} {incr i} {
+ array unset C
+ array set C [lindex $clist $i]
+ if {$C(usable)} {
+ if {[info exists binops($C(op))]} {
+ lappend ret omit $i
+ lappend str "$cols($C(column)) $binops($C(op)) %$v%"
+ incr v
+ set cost [expr $cost / 2]
+ }
+ if {[info exists unops($C(op))]} {
+ lappend ret omit $i
+ lappend str "$cols($C(column)) $unops($C(op))"
+ incr v
+ set cost [expr $cost / 2]
+ }
+ }
+ }
+
+ lappend ret idxstr [join $str " AND "]
+ lappend ret cost $cost
+ return $ret
+ }
+
+ xFilter {
+ set q [lindex $args 1]
+ set a [lindex $args 2]
+ for {set v 0} {$v < [llength $a]} {incr v} {
+ set val [lindex $a $v]
+ set q [string map [list %$v% '$val'] $q]
+ }
+ if {$q==""} { set q 1 }
+ lappend ::xFilterQueries "WHERE $q"
+ return [list sql "SELECT rowid, * FROM t1x WHERE $q"]
+ }
+ }
+ return ""
+}
+
+proc vtab_simple {method args} {
+ switch -- $method {
+ xConnect {
+ return "CREATE TABLE t2(x)"
+ }
+ xBestIndex {
+ return [list cost 999999.0]
+ }
+ xFilter {
+ return [list sql "SELECT rowid, * FROM t2x"]
+ }
+ }
+ return ""
+}
+
+register_tcl_module db
+
+proc do_vtab_query_test {tn query result} {
+ set ::xFilterQueries [list]
+ uplevel [list
+ do_test $tn [string map [list %QUERY% $query] {
+ set r [execsql {%QUERY%}]
+ set r [concat $::xFilterQueries $r]
+ set r
+ }] [list {*}$result]
+ ]
+}
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE t1 USING tcl('vtab_cmd');
+ CREATE TABLE t1x(a INTEGER, b TEXT, c REAL);
+ INSERT INTO t1x VALUES(1, 2, 3);
+ INSERT INTO t1x VALUES(4, 5, 6);
+ INSERT INTO t1x VALUES(7, 8, 9);
+
+ CREATE VIRTUAL TABLE t2 USING tcl('vtab_simple');
+ CREATE TABLE t2x(x INTEGER);
+ INSERT INTO t2x VALUES(1);
+}
+
+do_vtab_query_test 1.1 { SELECT * FROM t1 WHERE a!='hello'; } {
+ "WHERE a != 'hello'"
+ 1 2 3.0 4 5 6.0 7 8 9.0
+}
+
+do_vtab_query_test 1.2.1 { SELECT * FROM t1 WHERE b!=8 } {
+ "WHERE b != '8'"
+ 1 2 3.0 4 5 6.0
+}
+do_vtab_query_test 1.2.2 { SELECT * FROM t1 WHERE 8!=b } {
+ "WHERE b != '8'"
+ 1 2 3.0 4 5 6.0
+}
+
+do_vtab_query_test 1.3 { SELECT * FROM t1 WHERE c IS NOT 3 } {
+ "WHERE c IS NOT '3'"
+ 4 5 6.0 7 8 9.0
+}
+do_vtab_query_test 1.3.2 { SELECT * FROM t1 WHERE 3 IS NOT c } {
+ "WHERE c IS NOT '3'"
+ 4 5 6.0 7 8 9.0
+}
+
+do_vtab_query_test 1.4.1 { SELECT * FROM t1, t2 WHERE x != a } {
+ "WHERE a != '1'"
+ 4 5 6.0 1 7 8 9.0 1
+}
+do_vtab_query_test 1.4.2 { SELECT * FROM t1, t2 WHERE a != x } {
+ "WHERE a != '1'"
+ 4 5 6.0 1 7 8 9.0 1
+}
+
+do_vtab_query_test 1.5.1 { SELECT * FROM t1 WHERE a IS NOT NULL } {
+ "WHERE a IS NOT NULL"
+ 1 2 3.0 4 5 6.0 7 8 9.0
+}
+do_vtab_query_test 1.5.2 { SELECT * FROM t1 WHERE NULL IS NOT a } {
+ "WHERE a IS NOT ''"
+ 1 2 3.0 4 5 6.0 7 8 9.0
+}
+
+do_vtab_query_test 1.6.1 { SELECT * FROM t1 WHERE a IS NULL } {
+ "WHERE a IS NULL"
+}
+
+do_vtab_query_test 1.6.2 { SELECT * FROM t1 WHERE NULL IS a } {
+ "WHERE a IS ''"
+}
+
+do_vtab_query_test 1.7.1 { SELECT * FROM t1 WHERE (a, b) IS (1, 2) } {
+ "WHERE a IS '1' AND b IS '2'"
+ 1 2 3.0
+}
+do_vtab_query_test 1.7.2 { SELECT * FROM t1 WHERE (5, 4) IS (b, a) } {
+ {WHERE b IS '5' AND a IS '4'}
+ 4 5 6.0
+}
+
+#---------------------------------------------------------------------
+do_execsql_test 2.0.0 {
+ DELETE FROM t1x;
+ INSERT INTO t1x VALUES('a', 'b', 'c');
+}
+do_execsql_test 2.0.1 { SELECT * FROM t1 } {a b c}
+do_execsql_test 2.0.2 { SELECT * FROM t1 WHERE (a, b) != ('a', 'b'); } {}
+
+do_execsql_test 2.1.0 {
+ DELETE FROM t1x;
+ INSERT INTO t1x VALUES(7, 8, 9);
+}
+do_execsql_test 2.1.1 { SELECT * FROM t1 } {7 8 9.0}
+do_execsql_test 2.1.2 { SELECT * FROM t1 WHERE (a, b) != (7, '8') } {}
+do_execsql_test 2.1.3 { SELECT * FROM t1 WHERE a!=7 OR b!='8' }
+do_execsql_test 2.1.4 { SELECT * FROM t1 WHERE a!=7 OR b!='8' }
+
+
+do_execsql_test 2.2.1 {
+ CREATE TABLE t3(a INTEGER, b TEXT);
+ INSERT INTO t3 VALUES(45, 46);
+}
+do_execsql_test 2.2.2 { SELECT * FROM t3 WHERE (a, b) != (45, 46); }
+do_execsql_test 2.2.3 { SELECT * FROM t3 WHERE (a, b) != ('45', '46'); }
+do_execsql_test 2.2.4 { SELECT * FROM t3 WHERE (a, b) == (45, 46); } {45 46}
+do_execsql_test 2.2.5 { SELECT * FROM t3 WHERE (a, b) == ('45', '46'); } {45 46}
+
+#---------------------------------------------------------------------
+# Test the != operator on a virtual table with column affinities.
+#
+proc vtab_simple_integer {method args} {
+ switch -- $method {
+ xConnect {
+ return "CREATE TABLE t4(x INTEGER)"
+ }
+ xBestIndex {
+ return [list cost 999999.0]
+ }
+ xFilter {
+ return [list sql "SELECT rowid, * FROM t4x"]
+ }
+ }
+ return ""
+}
+
+do_execsql_test 3.0 {
+ CREATE TABLE t4x(a INTEGER);
+ INSERT INTO t4x VALUES(245);
+ CREATE VIRTUAL TABLE t4 USING tcl('vtab_simple_integer');
+}
+do_execsql_test 3.1 { SELECT rowid, * FROM t4 WHERE x=245; } {1 245}
+do_execsql_test 3.2 { SELECT rowid, * FROM t4 WHERE x='245'; } {1 245}
+do_execsql_test 3.3 { SELECT rowid, * FROM t4 WHERE x!=245; } {}
+do_execsql_test 3.4 { SELECT rowid, * FROM t4 WHERE x!='245'; } {}
+
+do_execsql_test 3.5 { SELECT rowid, * FROM t4 WHERE rowid!=1 OR x!='245'; } {}
+
+
+finish_test
+
diff --git a/third_party/sqlite/src/test/bigmmap.test b/third_party/sqlite/src/test/bigmmap.test
new file mode 100644
index 0000000..ce1f7b7
--- /dev/null
+++ b/third_party/sqlite/src/test/bigmmap.test
@@ -0,0 +1,104 @@
+# 2017 August 07
+#
+# 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 regression tests for SQLite library. The
+# focus of this script testing the ability of SQLite to use mmap
+# to access files larger than 4GiB.
+#
+
+if {[file exists skip-big-file]} return
+if {$tcl_platform(os)=="Darwin"} return
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix bigmmap
+
+ifcapable !mmap||!vtab {
+ finish_test
+ return
+}
+
+set mmap_limit 0
+db eval {
+ SELECT compile_options AS x FROM pragma_compile_options
+ WHERE x LIKE 'max_mmap_size=%'
+} {
+ regexp {MAX_MMAP_SIZE=([0-9]*)} $x -> mmap_limit
+}
+if {$mmap_limit < [expr 8 * 1<<30]} {
+ puts "Skipping bigmmap.test - requires SQLITE_MAX_MMAP_SIZE >= 8G"
+ finish_test
+ return
+}
+
+
+#-------------------------------------------------------------------------
+# Create the database file roughly 8GiB in size. Most pages are unused,
+# except that there is a table and index clustered around each 1GiB
+# boundary.
+#
+do_execsql_test 1.0 {
+ PRAGMA page_size = 4096;
+ CREATE TABLE t0(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
+ WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 100 )
+ INSERT INTO t0 SELECT i, 't0', randomblob(800) FROM s;
+}
+
+for {set i 1} {$i < 8} {incr i} {
+ fake_big_file [expr $i*1024] [get_pwd]/test.db
+ hexio_write test.db 28 [format %.8x [expr ($i*1024*1024*1024/4096) - 5]]
+
+ do_execsql_test 1.$i "
+ CREATE TABLE t$i (a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c));
+ WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 100 )
+ INSERT INTO t$i SELECT i, 't$i', randomblob(800) FROM s;
+ "
+}
+
+#-------------------------------------------------------------------------
+# Check that data can be retrieved from the db with a variety of
+# configured mmap size limits.
+#
+for {set i 0} {$i < 9} {incr i} {
+
+ # Configure a memory mapping $i GB in size.
+ #
+ set val [expr $i*1024*1024*1024]
+ execsql "PRAGMA main.mmap_size = $val"
+ do_execsql_test 2.$i.0 {
+ PRAGMA main.mmap_size
+ } $val
+
+ for {set t 0} {$t < 8} {incr t} {
+ do_execsql_test 2.$i.$t.1 "
+ SELECT count(*) FROM t$t;
+ SELECT count(b || c) FROM t$t GROUP BY b;
+ " {100 100}
+
+ do_execsql_test 2.$i.$t.2 "
+ SELECT * FROM t$t AS o WHERE
+ NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c )
+ ORDER BY b, c;
+ " {}
+
+ do_eqp_test 2.$i.$t.3 "
+ SELECT * FROM t$t AS o WHERE
+ NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c )
+ ORDER BY b, c;
+ " "
+ 0 0 0 {SCAN TABLE t$t AS o USING COVERING INDEX sqlite_autoindex_t${t}_1}
+ 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 1}
+ 1 0 0 {SEARCH TABLE t$t AS i USING INTEGER PRIMARY KEY (rowid=?)}
+ "
+ }
+}
+
+finish_test
+
diff --git a/third_party/sqlite/src/test/busy.test b/third_party/sqlite/src/test/busy.test
index 585f764..be0515b 100644
--- a/third_party/sqlite/src/test/busy.test
+++ b/third_party/sqlite/src/test/busy.test
@@ -10,11 +10,11 @@
#***********************************************************************
# This file test the busy handler
#
-# $Id: busy.test,v 1.3 2008/03/15 02:09:22 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
+set testprefix busy
do_test busy-1.1 {
sqlite3 db2 test.db
@@ -55,7 +55,85 @@ do_test busy-2.2 {
set busyargs
} {0 1 2 3}
-
db2 close
+#-------------------------------------------------------------------------
+# Test that the busy-handler is invoked correctly for "PRAGMA optimize"
+# and ANALYZE commnds.
+ifcapable pragma&&analyze&&!stat4 {
+
+reset_db
+
+do_execsql_test 3.1 {
+ CREATE TABLE t1(x);
+ CREATE TABLE t2(y);
+ CREATE TABLE t3(z);
+
+ CREATE INDEX i1 ON t1(x);
+ CREATE INDEX i2 ON t2(y);
+
+ INSERT INTO t1 VALUES(1);
+ INSERT INTO t2 VALUES(1);
+ ANALYZE;
+
+ SELECT * FROM t1 WHERE x=1;
+ SELECT * FROM t2 WHERE y=1;
+} {1 1}
+
+do_test 3.2 {
+ sqlite3 db2 test.db
+ execsql { BEGIN EXCLUSIVE } db2
+ catchsql { PRAGMA optimize }
+} {1 {database is locked}}
+
+proc busy_handler {n} {
+ if {$n>1000} { execsql { COMMIT } db2 }
+ return 0
+}
+db busy busy_handler
+
+do_test 3.3 {
+ catchsql { PRAGMA optimize }
+} {0 {}}
+
+do_test 3.4 {
+ execsql {
+ BEGIN;
+ SELECT count(*) FROM sqlite_master;
+ } db2
+} {6}
+
+proc busy_handler {n} { return 1 }
+do_test 3.5 {
+ catchsql { PRAGMA optimize }
+} {0 {}}
+
+do_test 3.6 {
+ execsql { COMMIT } db2
+ execsql {
+ WITH s(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000
+ )
+ INSERT INTO t1 SELECT i FROM s;
+ }
+ execsql {
+ BEGIN;
+ SELECT count(*) FROM sqlite_master;
+ } db2
+} {6}
+
+do_test 3.7 {
+ catchsql { PRAGMA optimize }
+} {1 {database is locked}}
+
+proc busy_handler {n} {
+ if {$n>1000} { execsql { COMMIT } db2 }
+ return 0
+}
+do_test 3.8 {
+ catchsql { PRAGMA optimize }
+} {0 {}}
+
+}
+
finish_test
diff --git a/third_party/sqlite/src/test/checkfreelist.test b/third_party/sqlite/src/test/checkfreelist.test
new file mode 100644
index 0000000..b2a45d3
--- /dev/null
+++ b/third_party/sqlite/src/test/checkfreelist.test
@@ -0,0 +1,123 @@
+# 2017-10-11
+#
+# 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 regression tests for SQLite library. The
+# focus of this file is testing the checkfreelist extension.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix checkfreelist
+
+ifcapable !vtab||!compound {
+ finish_test
+ return
+}
+
+if {[file exists ../checkfreelist.so]==0} {
+ finish_test
+ return
+}
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1(a, b);
+}
+
+db enable_load_extension 1
+do_execsql_test 1.1 {
+ SELECT load_extension('../checkfreelist.so');
+} {{}}
+
+do_execsql_test 1.2 { SELECT checkfreelist('main') } {ok}
+do_execsql_test 1.3 {
+ WITH s(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10000
+ )
+ INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s;
+ DELETE FROM t1 WHERE rowid%3;
+ PRAGMA freelist_count;
+} {6726}
+
+do_execsql_test 1.4 { SELECT checkfreelist('main') } {ok}
+do_execsql_test 1.5 {
+ WITH freelist_trunk(i, d, n) AS (
+ SELECT 1, NULL, sqlite_readint32(data, 32) FROM sqlite_dbpage WHERE pgno=1
+ UNION ALL
+ SELECT n, data, sqlite_readint32(data)
+ FROM freelist_trunk, sqlite_dbpage WHERE pgno=n
+ )
+ SELECT i FROM freelist_trunk WHERE i!=1;
+} {
+ 10010 9716 9344 8970 8596 8223 7848 7475 7103 6728 6355 5983 5609 5235
+ 4861 4488 4113 3741 3368 2993 2620 2248 1873 1500 1126 753 378 5
+}
+
+do_execsql_test 1.6 { SELECT checkfreelist('main') } {ok}
+
+proc set_int {blob idx newval} {
+ binary scan $blob I* ints
+ lset ints $idx $newval
+ binary format I* $ints
+}
+db func set_int set_int
+
+proc get_int {blob idx} {
+ binary scan $blob I* ints
+ lindex $ints $idx
+}
+db func get_int get_int
+
+do_execsql_test 1.7 {
+ BEGIN;
+ UPDATE sqlite_dbpage
+ SET data = set_int(data, 1, get_int(data, 1)-1)
+ WHERE pgno=4861;
+ SELECT checkfreelist('main');
+ ROLLBACK;
+} {{free-list count mismatch: actual=6725 header=6726}}
+
+do_execsql_test 1.8 {
+ BEGIN;
+ UPDATE sqlite_dbpage
+ SET data = set_int(data, 5, (SELECT * FROM pragma_page_count)+1)
+ WHERE pgno=4861;
+ SELECT checkfreelist('main');
+ ROLLBACK;
+} {{leaf page 10093 is out of range (child 3 of trunk page 4861)}}
+
+do_execsql_test 1.9 {
+ BEGIN;
+ UPDATE sqlite_dbpage
+ SET data = set_int(data, 5, 0)
+ WHERE pgno=4861;
+ SELECT checkfreelist('main');
+ ROLLBACK;
+} {{leaf page 0 is out of range (child 3 of trunk page 4861)}}
+
+do_execsql_test 1.10 {
+ BEGIN;
+ UPDATE sqlite_dbpage
+ SET data = set_int(data, get_int(data, 1)+1, 0)
+ WHERE pgno=5;
+ SELECT checkfreelist('main');
+ ROLLBACK;
+} {{leaf page 0 is out of range (child 247 of trunk page 5)}}
+
+do_execsql_test 1.11 {
+ BEGIN;
+ UPDATE sqlite_dbpage
+ SET data = set_int(data, 1, 249)
+ WHERE pgno=5;
+ SELECT checkfreelist('main');
+ ROLLBACK;
+} {{leaf count out of range (249) on trunk page 5}}
+
+finish_test
+
diff --git a/third_party/sqlite/src/test/colname.test b/third_party/sqlite/src/test/colname.test
index 37d152b..0f81ddf 100644
--- a/third_party/sqlite/src/test/colname.test
+++ b/third_party/sqlite/src/test/colname.test
@@ -326,4 +326,75 @@ do_test colname-8.1 {
}
} {123}
+# 2017-07-29: Interaction between column naming and query flattening.
+# For years now, the query flattener has inserted AS clauses on the
+# outer query that were the original SQL text of the column. This caused
+# column-name shifts when the query flattener was enhanced, breaking
+# legacy applications. See https://sqlite.org/src/info/41c27bc0ff1d3135
+# for details.
+#
+# To fix this, the column naming logic was moved ahead of the query
+# flattener so that column names are assigned before the query flattener
+# runs.
+#
+db close
+sqlite3 db :memory:
+do_test colname-9.100 {
+ db eval {
+ CREATE TABLE t1(a,b);
+ INSERT INTO t1 VALUES(1,2);
+ CREATE VIEW v1(x,y) AS SELECT a,b FROM t1;
+ }
+ execsql2 {SELECT v1.x, (Y) FROM v1}
+ # Prior to the fix, this would return: "v1.x 1 (Y) 2"
+} {x 1 y 2}
+do_test colname-9.110 {
+ execsql2 {SELECT * FROM v1}
+} {x 1 y 2}
+do_test colname-9.120 {
+ db eval {
+ CREATE VIEW v2(x,y) AS SELECT a,b FROM t1 LIMIT 10;
+ }
+ execsql2 {SELECT * FROM v2 WHERE 1}
+} {x 1 y 2}
+do_test colname-9.130 {
+ execsql2 {SELECT v2.x, [v2].[y] FROM v2 WHERE 1}
+} {x 1 y 2}
+do_test colname-9.140 {
+ execsql2 {SELECT +x, +y FROM v2 WHERE 1}
+} {+x 1 +y 2}
+
+do_test colname-9.200 {
+ db eval {
+ CREATE TABLE t2(c,d);
+ INSERT INTO t2 VALUES(3,4);
+ CREATE VIEW v3 AS SELECT c AS a, d AS b FROM t2;
+ }
+ execsql2 {SELECT t1.a, v3.a AS n FROM t1 LEFT JOIN v3}
+} {a 1 n 3}
+do_test colname-9.211 {
+ execsql2 {SELECT t1.a AS n, v3.a FROM t1 JOIN v3}
+} {n 1 a 3}
+do_test colname-9.210 {
+ execsql2 {SELECT t1.a, v3.a AS n FROM t1 JOIN v3}
+} {a 1 n 3}
+
+# Make sure the quotation marks get removed from the column names
+# when constructing a new table from an aggregate SELECT.
+# Email from Juergen Palm on 2017-07-11.
+#
+do_execsql_test colname-10.100 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1("with space" TEXT);
+ DROP TABLE IF EXISTS t2;
+ CREATE TABLE t2 AS SELECT "with space" FROM t1;
+ PRAGMA table_info(t2);
+} {0 {with space} TEXT 0 {} 0}
+do_execsql_test colname-10.110 {
+ DROP TABLE IF EXISTS t3;
+ CREATE TABLE t3 AS SELECT "with space" FROM t1 GROUP BY 1;
+ PRAGMA table_info(t3);
+} {0 {with space} TEXT 0 {} 0}
+
+
finish_test
diff --git a/third_party/sqlite/src/test/corruptC.test b/third_party/sqlite/src/test/corruptC.test
index 8c7f2e6..d994354 100644
--- a/third_party/sqlite/src/test/corruptC.test
+++ b/third_party/sqlite/src/test/corruptC.test
@@ -164,7 +164,7 @@ do_test corruptC-2.5 {
catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
catchsql {PRAGMA integrity_check}
} {0 {{*** in database main ***
-On tree page 4 cell 19: Extends off end of page}}}
+On tree page 4 cell 19: Extends off end of page} {database disk image is malformed}}}
# {0 {{*** in database main ***
# Corruption detected in cell 710 on page 4
diff --git a/third_party/sqlite/src/test/corruptK.test b/third_party/sqlite/src/test/corruptK.test
index 0b8a85d..9bbc470 100644
--- a/third_party/sqlite/src/test/corruptK.test
+++ b/third_party/sqlite/src/test/corruptK.test
@@ -107,6 +107,121 @@ do_catchsql_test 2.3 {
INSERT INTO t1 VALUES(randomblob(900));
} {1 {database disk image is malformed}}
+#-------------------------------------------------------------------------
+
+ifcapable vtab {
+if {[permutation]!="inmemory_journal"} {
+
+ proc hex2blob {hex} {
+ # Split on newlines:
+ set bytes [list]
+ foreach l [split $hex "\n"] {
+ if {[string is space $l]} continue
+ set L [list]
+ foreach b [split $l] {
+ if {[string is xdigit $b] && [string length $b]==2} {
+ lappend L [expr "0x$b"]
+ }
+ }
+ if {[llength $L]!=16} {
+ error "Badly formed hex (1)"
+ }
+ set bytes [concat $bytes $L]
+ }
+
+ binary format c* $bytes
+ }
+
+ reset_db
+ db func hex2blob hex2blob
+
+ do_execsql_test 3.1 {
+ PRAGMA page_size=1024;
+ CREATE TABLE t1(a, b, c);
+ CREATE TABLE t2(a, b, c);
+ CREATE TABLE t3(a, b, c);
+ CREATE TABLE t4(a, b, c);
+ CREATE TABLE t5(a, b, c);
+ }
+
+ do_execsql_test 3.2 {
+ UPDATE sqlite_dbpage SET data = hex2blob('
+ 000: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+ 010: 04 00 01 01 20 40 20 20 00 00 3e d9 00 00 00 06 .... @ ..>.....
+ 020: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
+ 030: 0f 00 00 00 00 00 00 00 00 00 00 01 00 00 83 00 ................
+ 040: 00 00 00 00 00 00 00 00 00 00 00 00 00 38 00 00 .............8..
+ 050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3e d9 ..............>.
+ 060: 00 2d e6 07 0d 00 00 00 01 03 a0 00 03 e0 00 00 .-..............
+ 070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 0a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 0b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 0c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 0d0: 00 00 00 00 00 c1 00 00 00 00 00 00 00 00 00 00 ................
+ 0e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 0f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 160: 00 83 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 180: 00 00 00 00 00 00 00 00 00 00 07 00 30 00 00 00 ............0...
+ 190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 1a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 1b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 1c0: 02 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 ................
+ 1d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 1e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 1f0: 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 220: 00 00 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 230: 0c 00 00 00 00 00 00 60 00 00 00 06 00 00 c3 00 .......`........
+ 240: 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 270: 00 00 00 18 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 290: 04 00 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 2a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 2b0: 00 00 00 00 83 00 8c 00 00 00 00 00 00 00 00 00 ................
+ 2c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 2d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 2e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 2f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 310: 00 78 00 00 00 00 00 00 00 00 00 00 00 00 70 00 .x............p.
+ 320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 340: 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 350: 00 00 00 00 00 68 00 00 00 00 00 00 00 00 00 00 .....h..........
+ 360: 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 ................
+ 370: 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 ................
+ 380: 00 00 00 00 70 00 00 00 00 00 00 00 00 00 00 00 ....p...........
+ 390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ 3a0: 5e 01 07 17 1b 1b 01 81 13 74 61 62 6c 65 73 65 ^........tablese
+ 3b0: 6e 73 6f 32 73 73 65 6e 73 6f 72 73 02 43 52 45 nso2ssensors.CRE
+ 3c0: 41 54 45 20 54 41 42 4c 45 20 73 65 6e 73 6f 72 ATE TABLE sensor
+ 3d0: 73 20 0a 20 20 24 20 20 20 20 20 20 20 20 20 20 s . $
+ 3e0: b8 6e 61 6d 65 21 74 65 78 74 2c 20 79 61 6c 20 .name!text, yal
+ 3f0: 72 65 61 6c 2c 20 74 69 6d 65 20 74 65 78 74 29 real, time text)
+ ') WHERE pgno=1
+ }
+
+ db close
+ sqlite3 db test.db
+
+ do_catchsql_test 3.3 {
+ PRAGMA integrity_check;
+ } {1 {database disk image is malformed}}
+
+} ;# [permutation]!="inmemory_journal"
+} ;# ifcapable vtab
diff --git a/third_party/sqlite/src/test/csv01.test b/third_party/sqlite/src/test/csv01.test
index f4c68e4..8b7759f 100644
--- a/third_party/sqlite/src/test/csv01.test
+++ b/third_party/sqlite/src/test/csv01.test
@@ -93,6 +93,7 @@ do_catchsql_test 3.2 {
SELECT rowid, a FROM t3;
} {1 {no such column: rowid}}
+# Multi-column WITHOUT ROWID virtual tables may not be writable.
do_catchsql_test 4.0 {
DROP TABLE t3;
CREATE VIRTUAL TABLE temp.t4 USING csv_wr(
@@ -100,13 +101,44 @@ do_catchsql_test 4.0 {
'1,2,3,4
5,6,7,8
9,10,11,12
-13,14,15,16
-',
+13,14,15,16',
columns=4,
schema=
- 'CREATE TABLE t3(a PRIMARY KEY,b TEXT,c TEXT,d TEXT) WITHOUT ROWID',
+ 'CREATE TABLE t3(a,b,c,d,PRIMARY KEY(a,b)) WITHOUT ROWID',
testflags=1
);
} {1 {vtable constructor failed: t4}}
+# WITHOUT ROWID tables with a single-column PRIMARY KEY may be writable.
+do_catchsql_test 4.1 {
+ DROP TABLE IF EXISTS t4;
+ CREATE VIRTUAL TABLE temp.t4 USING csv_wr(
+ data=
+'1,2,3,4
+5,6,7,8
+9,10,11,12
+13,14,15,16',
+ columns=4,
+ schema=
+ 'CREATE TABLE t3(a,b,c,d,PRIMARY KEY(b)) WITHOUT ROWID',
+ testflags=1
+ );
+} {0 {}}
+
+do_catchsql_test 4.2 {
+ DROP TABLE IF EXISTS t5;
+ CREATE VIRTUAL TABLE temp.t5 USING csv_wr(
+ data=
+ '1,2,3,4
+ 5,6,7,8
+ 9,10,11,12
+ 13,14,15,16',
+ columns=4,
+ schema=
+ 'CREATE TABLE t3(a,b,c,d) WITHOUT ROWID',
+ testflags=1
+ );
+} {1 {vtable constructor failed: t5}}
+
+
finish_test
diff --git a/third_party/sqlite/src/test/dbpage.test b/third_party/sqlite/src/test/dbpage.test
new file mode 100644
index 0000000..ff79b3e
--- /dev/null
+++ b/third_party/sqlite/src/test/dbpage.test
@@ -0,0 +1,74 @@
+# 2017-10-11
+#
+# 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 regression tests for SQLite library. The
+# focus of this file is testing the sqlite_dbpage virtual table.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix dbpage
+
+ifcapable !vtab||!compound {
+ finish_test
+ return
+}
+
+do_test 100 {
+ execsql {
+ PRAGMA auto_vacuum=0;
+ PRAGMA page_size=4096;
+ PRAGMA journal_mode=WAL;
+ }
+ execsql {
+ CREATE TABLE t1(a,b);
+ WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
+ INSERT INTO t1(a,b) SELECT x, printf('%d-x%.*c',x,x,'x') FROM c;
+ PRAGMA integrity_check;
+ }
+} {ok}
+do_execsql_test 110 {
+ SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage('main') ORDER BY pgno;
+} {1 X'53514C6974' 2 X'0500000001' 3 X'0D0000004E' 4 X'0D00000016'}
+do_execsql_test 120 {
+ SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=2;
+} {2 X'0500000001'}
+do_execsql_test 130 {
+ SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=4;
+} {4 X'0D00000016'}
+do_execsql_test 140 {
+ SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=5;
+} {}
+do_execsql_test 150 {
+ SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage WHERE pgno=0;
+} {}
+
+do_execsql_test 200 {
+ CREATE TEMP TABLE saved_content(x);
+ INSERT INTO saved_content(x) SELECT data FROM sqlite_dbpage WHERE pgno=4;
+ UPDATE sqlite_dbpage SET data=zeroblob(4096) WHERE pgno=4;
+} {}
+do_catchsql_test 210 {
+ PRAGMA integrity_check;
+} {1 {database disk image is malformed}}
+do_execsql_test 220 {
+ SELECT pgno, quote(substr(data,1,5)) FROM sqlite_dbpage('main') ORDER BY pgno;
+} {1 X'53514C6974' 2 X'0500000001' 3 X'0D0000004E' 4 X'0000000000'}
+do_execsql_test 230 {
+ UPDATE sqlite_dbpage SET data=(SELECT x FROM saved_content) WHERE pgno=4;
+} {}
+do_catchsql_test 230 {
+ PRAGMA integrity_check;
+} {0 ok}
+
+
+
+
+finish_test
diff --git a/third_party/sqlite/src/test/e_expr.test b/third_party/sqlite/src/test/e_expr.test
index de57af6..d239df0 100644
--- a/third_party/sqlite/src/test/e_expr.test
+++ b/third_party/sqlite/src/test/e_expr.test
@@ -1663,6 +1663,50 @@ do_expr_test e_expr-32.2.3 {
do_expr_test e_expr-32.2.4 {
CAST(9223372036854775807 AS NUMERIC)
} integer 9223372036854775807
+do_expr_test e_expr-32.2.5 {
+ CAST('9223372036854775807 ' AS NUMERIC)
+} integer 9223372036854775807
+do_expr_test e_expr-32.2.6 {
+ CAST(' 9223372036854775807 ' AS NUMERIC)
+} integer 9223372036854775807
+do_expr_test e_expr-32.2.7 {
+ CAST(' ' AS NUMERIC)
+} integer 0
+do_execsql_test e_expr-32.2.8 {
+ WITH t1(x) AS (VALUES
+ ('9000000000000000001'),
+ ('9000000000000000001x'),
+ ('9000000000000000001 '),
+ (' 9000000000000000001 '),
+ (' 9000000000000000001'),
+ (' 9000000000000000001.'),
+ ('9223372036854775807'),
+ ('9223372036854775807 '),
+ (' 9223372036854775807 '),
+ ('9223372036854775808'),
+ (' 9223372036854775808 '),
+ ('9223372036854775807.0'),
+ ('9223372036854775807e+0'),
+ ('-5.0'),
+ ('-5e+0'))
+ SELECT typeof(CAST(x AS NUMERIC)), CAST(x AS NUMERIC)||'' FROM t1;
+} [list \
+ integer 9000000000000000001 \
+ integer 9000000000000000001 \
+ integer 9000000000000000001 \
+ integer 9000000000000000001 \
+ integer 9000000000000000001 \
+ integer 9000000000000000001 \
+ integer 9223372036854775807 \
+ integer 9223372036854775807 \
+ integer 9223372036854775807 \
+ real 9.22337203685478e+18 \
+ real 9.22337203685478e+18 \
+ integer 9223372036854775807 \
+ integer 9223372036854775807 \
+ integer -5 \
+ integer -5 \
+]
# EVIDENCE-OF: R-64550-29191 Note that the result from casting any
# non-BLOB value into a BLOB and the result from casting any BLOB value
diff --git a/third_party/sqlite/src/test/e_uri.test b/third_party/sqlite/src/test/e_uri.test
index 71da32e..554805b 100644
--- a/third_party/sqlite/src/test/e_uri.test
+++ b/third_party/sqlite/src/test/e_uri.test
@@ -50,8 +50,8 @@ proc open_uri_error {uri} {
# and the filename argument begins with "file:", then the filename is
# interpreted as a URI.
#
-# EVIDENCE-OF: R-24124-56960 URI filename interpretation is enabled if
-# the SQLITE_OPEN_URI flag is set in the fourth argument to
+# EVIDENCE-OF: R-27632-24205 URI filename interpretation is enabled if
+# the SQLITE_OPEN_URI flag is set in the third argument to
# sqlite3_open_v2(), or if it has been enabled globally using the
# SQLITE_CONFIG_URI option with the sqlite3_config() method or by the
# SQLITE_USE_URI compile-time option.
diff --git a/third_party/sqlite/src/test/eqp.test b/third_party/sqlite/src/test/eqp.test
index dd2753f..12e916d 100644
--- a/third_party/sqlite/src/test/eqp.test
+++ b/third_party/sqlite/src/test/eqp.test
@@ -188,24 +188,24 @@ do_eqp_test 3.1.1 {
do_eqp_test 3.1.2 {
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub);
} {
+ 0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub}
- 0 0 0 {SCAN TABLE t1}
}
do_eqp_test 3.1.3 {
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y);
} {
+ 0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
- 0 0 0 {SCAN TABLE t1}
}
do_eqp_test 3.1.4 {
SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x);
} {
+ 0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
- 0 0 0 {SCAN TABLE t1}
}
det 3.2.1 {
diff --git a/third_party/sqlite/src/test/fallocate.test b/third_party/sqlite/src/test/fallocate.test
index 1325b74..a37ff13 100644
--- a/third_party/sqlite/src/test/fallocate.test
+++ b/third_party/sqlite/src/test/fallocate.test
@@ -59,7 +59,9 @@ do_test fallocate-1.6 {
#
do_test fallocate-1.7 {
execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); }
- if {[permutation] != "inmemory_journal"} {
+ if {[permutation] != "inmemory_journal"
+ && [permutation] != "atomic-batch-write"
+ } {
hexio_get_int [hexio_read test.db-journal 16 4]
} else {
set {} 1024
diff --git a/third_party/sqlite/src/test/fts3conf.test b/third_party/sqlite/src/test/fts3conf.test
index 2c6d821..4a2e315 100644
--- a/third_party/sqlite/src/test/fts3conf.test
+++ b/third_party/sqlite/src/test/fts3conf.test
@@ -136,47 +136,49 @@ do_execsql_test 2.2.2 { COMMIT }
do_execsql_test 2.2.3 { SELECT * FROM t1 } {{a b c} {a b c}}
fts3_integrity 2.2.4 db t1
-do_execsql_test 3.1 {
- CREATE VIRTUAL TABLE t3 USING fts4;
- REPLACE INTO t3(docid, content) VALUES (1, 'one two');
- SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
-} {X'0100000002000000'}
-
-do_execsql_test 3.2 {
- REPLACE INTO t3(docid, content) VALUES (2, 'one two three four');
- SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'four'
-} {X'0200000003000000'}
-
-do_execsql_test 3.3 {
- REPLACE INTO t3(docid, content) VALUES (1, 'one two three four five six');
- SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
-} {X'0200000005000000'}
-
-do_execsql_test 3.4 {
- UPDATE OR REPLACE t3 SET docid = 2 WHERE docid=1;
- SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
-} {X'0100000006000000'}
-
-do_execsql_test 3.5 {
- UPDATE OR REPLACE t3 SET docid = 3 WHERE docid=2;
- SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
-} {X'0100000006000000'}
-
-do_execsql_test 3.6 {
- REPLACE INTO t3(docid, content) VALUES (3, 'one two');
- SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
-} {X'0100000002000000'}
-
-do_execsql_test 3.7 {
- REPLACE INTO t3(docid, content) VALUES (NULL, 'one two three four');
- REPLACE INTO t3(docid, content) VALUES (NULL, 'one two three four five six');
- SELECT docid FROM t3;
-} {3 4 5}
-
-do_execsql_test 3.8 {
- UPDATE OR REPLACE t3 SET docid = 5, content='three four' WHERE docid = 4;
- SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
-} {X'0200000002000000'}
+if {$tcl_platform(byteOrder)=="littleEndian"} {
+ do_execsql_test 3.1 {
+ CREATE VIRTUAL TABLE t3 USING fts4;
+ REPLACE INTO t3(docid, content) VALUES (1, 'one two');
+ SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
+ } {X'0100000002000000'}
+
+ do_execsql_test 3.2 {
+ REPLACE INTO t3(docid, content) VALUES (2, 'one two three four');
+ SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'four'
+ } {X'0200000003000000'}
+
+ do_execsql_test 3.3 {
+ REPLACE INTO t3(docid, content) VALUES (1, 'one two three four five six');
+ SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
+ } {X'0200000005000000'}
+
+ do_execsql_test 3.4 {
+ UPDATE OR REPLACE t3 SET docid = 2 WHERE docid=1;
+ SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
+ } {X'0100000006000000'}
+
+ do_execsql_test 3.5 {
+ UPDATE OR REPLACE t3 SET docid = 3 WHERE docid=2;
+ SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'six'
+ } {X'0100000006000000'}
+
+ do_execsql_test 3.6 {
+ REPLACE INTO t3(docid, content) VALUES (3, 'one two');
+ SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
+ } {X'0100000002000000'}
+
+ do_execsql_test 3.7 {
+ REPLACE INTO t3(docid, content) VALUES(NULL,'one two three four');
+ REPLACE INTO t3(docid, content) VALUES(NULL,'one two three four five six');
+ SELECT docid FROM t3;
+ } {3 4 5}
+
+ do_execsql_test 3.8 {
+ UPDATE OR REPLACE t3 SET docid = 5, content='three four' WHERE docid = 4;
+ SELECT quote(matchinfo(t3, 'na')) FROM t3 WHERE t3 MATCH 'one'
+ } {X'0200000002000000'}
+}
#-------------------------------------------------------------------------
# Test that the xSavepoint is invoked correctly if the first write
diff --git a/third_party/sqlite/src/test/fts3rank.test b/third_party/sqlite/src/test/fts3rank.test
new file mode 100644
index 0000000..93b8c45
--- /dev/null
+++ b/third_party/sqlite/src/test/fts3rank.test
@@ -0,0 +1,64 @@
+# 2017 October 7
+#
+# 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 regression tests for SQLite library. The
+# focus of this script is testing the FTS3 module.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix fts3expr5
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts3 {
+ finish_test
+ return
+}
+
+install_fts3_rank_function db
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE t1 USING fts3(a, b);
+ INSERT INTO t1 VALUES('one two', 'one');
+ INSERT INTO t1 VALUES('one two', 'three');
+ INSERT INTO t1 VALUES('one two', 'two');
+}
+
+do_execsql_test 1.1 {
+ SELECT * FROM t1 WHERE t1 MATCH 'one'
+ ORDER BY rank(matchinfo(t1), 1.0, 1.0) DESC, rowid
+} {
+ {one two} one
+ {one two} three
+ {one two} two
+}
+
+do_execsql_test 1.2 {
+ SELECT * FROM t1 WHERE t1 MATCH 'two'
+ ORDER BY rank(matchinfo(t1), 1.0, 1.0) DESC, rowid
+} {
+ {one two} two
+ {one two} one
+ {one two} three
+}
+
+do_catchsql_test 1.3 {
+ SELECT * FROM t1 ORDER BY rank(matchinfo(t1), 1.0, 1.0) DESC, rowid
+} {1 {invalid matchinfo blob passed to function rank()}}
+
+do_catchsql_test 1.4 {
+ SELECT * FROM t1 ORDER BY rank(x'0000000000000000') DESC, rowid
+} {0 {{one two} one {one two} three {one two} two}}
+
+do_catchsql_test 1.5 {
+ SELECT * FROM t1 ORDER BY rank(x'0100000001000000') DESC, rowid
+} {1 {invalid matchinfo blob passed to function rank()}}
+
+finish_test
+
diff --git a/third_party/sqlite/src/test/having.test b/third_party/sqlite/src/test/having.test
index b790b44..bece7d7 100644
--- a/third_party/sqlite/src/test/having.test
+++ b/third_party/sqlite/src/test/having.test
@@ -65,19 +65,6 @@ foreach {tn sql1 sql2} {
3 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING a=2"
"SELECT a, sum(b) FROM t1 WHERE a=2 GROUP BY a COLLATE binary"
- 4 {
- SELECT x,y FROM (
- SELECT a AS x, sum(b) AS y FROM t1
- GROUP BY a
- ) WHERE x BETWEEN 8888 AND 9999
- } {
- SELECT x,y FROM (
- SELECT a AS x, sum(b) AS y FROM t1
- WHERE x BETWEEN 8888 AND 9999
- GROUP BY a
- )
- }
-
5 "SELECT a, sum(b) FROM t1 GROUP BY a COLLATE binary HAVING 0"
"SELECT a, sum(b) FROM t1 WHERE 0 GROUP BY a COLLATE binary"
@@ -98,6 +85,24 @@ foreach {tn sql1 sql2} {
do_compare_vdbe_test 2.$tn $sql1 $sql2 1
}
+# The (4) test in the above set used to generate identical bytecode, but
+# that is no longer the case. The byte code is equivalent, though.
+#
+do_execsql_test 2.4a {
+ SELECT x,y FROM (
+ SELECT a AS x, sum(b) AS y FROM t1
+ GROUP BY a
+ ) WHERE x BETWEEN 2 AND 9999
+} {2 12}
+do_execsql_test 2.4b {
+ SELECT x,y FROM (
+ SELECT a AS x, sum(b) AS y FROM t1
+ WHERE x BETWEEN 2 AND 9999
+ GROUP BY a
+ )
+} {2 12}
+
+
#-------------------------------------------------------------------------
# 1: Test that the optimization is only applied if the GROUP BY term
# uses BINARY collation.
diff --git a/third_party/sqlite/src/test/indexexpr1.test b/third_party/sqlite/src/test/indexexpr1.test
index d5fdc13..0f0dafc 100644
--- a/third_party/sqlite/src/test/indexexpr1.test
+++ b/third_party/sqlite/src/test/indexexpr1.test
@@ -380,7 +380,26 @@ do_execsql_test indexexpr1-1300.1 {
SELECT a FROM t1300 WHERE substr(b,4)='ess' COLLATE nocase ORDER BY +a;
} {3 4}
-# Date and time functions can participate in an index as long as they
-# do not contain
+# Ticket https://sqlite.org/src/tktview/aa98619a
+# Assertion fault using an index on a constant
+#
+do_execsql_test indexexpr1-1400 {
+ CREATE TABLE t1400(x TEXT);
+ CREATE INDEX t1400x ON t1400(1); -- Index on a constant
+ SELECT 1 IN (SELECT 2) FROM t1400;
+} {}
+do_execsql_test indexexpr1-1410 {
+ INSERT INTO t1400 VALUES('a'),('b');
+ SELECT 1 IN (SELECT 2) FROM t1400;
+} {0 0}
+do_execsql_test indexexpr1-1420 {
+ SELECT 1 IN (SELECT 2 UNION ALL SELECT 1) FROM t1400;
+} {1 1}
+do_execsql_test indexexpr1-1430 {
+ DROP INDEX t1400x;
+ CREATE INDEX t1400x ON t1400(abs(15+3));
+ SELECT abs(15+3) IN (SELECT 17 UNION ALL SELECT 18) FROM t1;
+} {1 1}
+
finish_test
diff --git a/third_party/sqlite/src/test/indexexpr2.test b/third_party/sqlite/src/test/indexexpr2.test
index c72561f..a6b43cb 100644
--- a/third_party/sqlite/src/test/indexexpr2.test
+++ b/third_party/sqlite/src/test/indexexpr2.test
@@ -40,4 +40,122 @@ do_execsql_test 2.1 {
SELECT a+1, quote(a+1) FROM t1 ORDER BY 1;
} {2 2 3 3 4 4}
+#-------------------------------------------------------------------------
+# At one point SQLite was incorrectly using indexes on expressions to
+# optimize ORDER BY and GROUP BY clauses even when the collation
+# sequences of the query and index did not match (ticket [e20dd54ab0e4]).
+# The following tests - 3.* - attempt to verify that this has been fixed.
+#
+
+reset_db
+do_execsql_test 3.1.0 {
+ CREATE TABLE t1(a, b);
+ CREATE INDEX i1 ON t1(a, b);
+} {}
+
+do_eqp_test 3.1.1 {
+ SELECT b FROM t1 WHERE b IS NOT NULL AND a IS NULL
+ GROUP BY b COLLATE nocase
+ ORDER BY b COLLATE nocase;
+} {/USE TEMP B-TREE FOR GROUP BY/}
+
+do_execsql_test 3.2.0 {
+ CREATE TABLE t2(x);
+
+ INSERT INTO t2 VALUES('.ABC');
+ INSERT INTO t2 VALUES('.abcd');
+ INSERT INTO t2 VALUES('.defg');
+ INSERT INTO t2 VALUES('.DEF');
+} {}
+
+do_execsql_test 3.2.1 {
+ SELECT x FROM t2 ORDER BY substr(x, 2) COLLATE nocase;
+} {
+ .ABC .abcd .DEF .defg
+}
+
+do_execsql_test 3.2.2 {
+ CREATE INDEX i2 ON t2( substr(x, 2) );
+ SELECT x FROM t2 ORDER BY substr(x, 2) COLLATE nocase;
+} {
+ .ABC .abcd .DEF .defg
+}
+
+do_execsql_test 3.3.0 {
+ CREATE TABLE t3(x);
+}
+
+ifcapable json1 {
+ do_eqp_test 3.3.1 {
+ SELECT json_extract(x, '$.b') FROM t2
+ WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL
+ GROUP BY json_extract(x, '$.b') COLLATE nocase
+ ORDER BY json_extract(x, '$.b') COLLATE nocase;
+ } {
+ 0 0 0 {SCAN TABLE t2}
+ 0 0 0 {USE TEMP B-TREE FOR GROUP BY}
+ }
+
+ do_execsql_test 3.3.2 {
+ CREATE INDEX i3 ON t3(json_extract(x, '$.a'), json_extract(x, '$.b'));
+ } {}
+
+ do_eqp_test 3.3.3 {
+ SELECT json_extract(x, '$.b') FROM t3
+ WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL
+ GROUP BY json_extract(x, '$.b') COLLATE nocase
+ ORDER BY json_extract(x, '$.b') COLLATE nocase;
+ } {
+ 0 0 0 {SEARCH TABLE t3 USING INDEX i3 (<expr>=?)}
+ 0 0 0 {USE TEMP B-TREE FOR GROUP BY}
+ }
+}
+
+do_execsql_test 3.4.0 {
+ CREATE TABLE t4(a, b);
+ INSERT INTO t4 VALUES('.ABC', 1);
+ INSERT INTO t4 VALUES('.abc', 2);
+ INSERT INTO t4 VALUES('.ABC', 3);
+ INSERT INTO t4 VALUES('.abc', 4);
+}
+
+do_execsql_test 3.4.1 {
+ SELECT * FROM t4
+ WHERE substr(a, 2) = 'abc' COLLATE NOCASE
+ ORDER BY substr(a, 2), b;
+} {
+ .ABC 1 .ABC 3 .abc 2 .abc 4
+}
+
+do_execsql_test 3.4.2 {
+ CREATE INDEX i4 ON t4( substr(a, 2) COLLATE NOCASE, b );
+ SELECT * FROM t4
+ WHERE substr(a, 2) = 'abc' COLLATE NOCASE
+ ORDER BY substr(a, 2), b;
+} {
+ .ABC 1 .ABC 3 .abc 2 .abc 4
+}
+
+do_execsql_test 3.4.3 {
+ DROP INDEX i4;
+ UPDATE t4 SET a = printf('%s%d',a,b);
+ SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase;
+} {.ABC1 1 .abc2 2 .ABC3 3 .abc4 4}
+do_execsql_test 3.4.4 {
+ SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE binary;
+} {.ABC1 1 .ABC3 3 .abc2 2 .abc4 4}
+
+do_execsql_test 3.4.5 {
+ CREATE INDEX i4 ON t4( Substr(a,-2) COLLATE nocase );
+ SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase;
+} {.ABC1 1 .abc2 2 .ABC3 3 .abc4 4}
+do_execsql_test 3.4.5eqp {
+ EXPLAIN QUERY PLAN
+ SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase;
+} {/SCAN TABLE t4 USING INDEX i4/}
+do_execsql_test 3.4.6 {
+ SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE binary;
+} {.ABC1 1 .ABC3 3 .abc2 2 .abc4 4}
+
+
finish_test
diff --git a/third_party/sqlite/src/test/kvtest.c b/third_party/sqlite/src/test/kvtest.c
index 97c0d10..54150f4 100644
--- a/third_party/sqlite/src/test/kvtest.c
+++ b/third_party/sqlite/src/test/kvtest.c
@@ -741,16 +741,6 @@ static int display_stats(
"Number of Pcache Overflow Bytes: %d (max %d) bytes\n",
iCur, iHiwtr);
iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
- fprintf(out,
- "Number of Scratch Allocations Used: %d (max %d)\n",
- iCur, iHiwtr);
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
- fprintf(out,
- "Number of Scratch Overflow Bytes: %d (max %d) bytes\n",
- iCur, iHiwtr);
- iHiwtr = iCur = -1;
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
fprintf(out, "Largest Allocation: %d bytes\n",
iHiwtr);
@@ -758,10 +748,6 @@ static int display_stats(
sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
fprintf(out, "Largest Pcache Allocation: %d bytes\n",
iHiwtr);
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
- fprintf(out, "Largest Scratch Allocation: %d bytes\n",
- iHiwtr);
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
diff --git a/third_party/sqlite/src/test/like.test b/third_party/sqlite/src/test/like.test
index 048486f..e50671b 100644
--- a/third_party/sqlite/src/test/like.test
+++ b/third_party/sqlite/src/test/like.test
@@ -207,7 +207,7 @@ do_test like-3.3.100 {
SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
}
} {abc abcd nosort {} i1}
-do_test like-3.3.101 {
+do_test like-3.3.100.cnt {
set sqlite_like_count
} 0
@@ -1048,4 +1048,51 @@ ifcapable !icu {
} {1}
}
+ifcapable !icu {
+# As of 2017-07-27 (3.21.0) the LIKE optimization works with ESCAPE as
+# long as the ESCAPE is a single-byte literal.
+#
+db close
+sqlite3 db :memory:
+do_execsql_test like-15.100 {
+ CREATE TABLE t15(x TEXT COLLATE nocase, y, PRIMARY KEY(x));
+ INSERT INTO t15(x,y) VALUES
+ ('abcde',1), ('ab%de',2), ('a_cde',3),
+ ('uvwxy',11),('uvwx%',12),('uvwx_',13),
+ ('_bcde',21),('%bcde',22),
+ ('abcd_',31),('abcd%',32),
+ ('ab%xy',41);
+ SELECT y FROM t15 WHERE x LIKE 'ab/%d%' ESCAPE '/';
+} {2}
+do_execsql_test like-15.101 {
+ EXPLAIN QUERY PLAN
+ SELECT y FROM t15 WHERE x LIKE 'ab/%d%' ESCAPE '/';
+} {/SEARCH/}
+do_execsql_test like-15.102 {
+ EXPLAIN QUERY PLAN
+ SELECT y FROM t15 WHERE x LIKE 'ab/%d%' ESCAPE '//';
+} {/SCAN/}
+do_execsql_test like-15.103 {
+ EXPLAIN QUERY PLAN
+ SELECT y FROM t15 WHERE x LIKE 'ab/%d%' ESCAPE '';
+} {/SCAN/}
+do_execsql_test like-15.110 {
+ SELECT y FROM t15 WHERE x LIKE 'abcdx%%' ESCAPE 'x';
+} {32}
+do_execsql_test like-15.111 {
+ SELECT y FROM t15 WHERE x LIKE 'abx%%' ESCAPE 'x' ORDER BY +y
+} {2 41}
+do_execsql_test like-15.112 {
+ EXPLAIN QUERY PLAN
+ SELECT y FROM t15 WHERE x LIKE 'abx%%' ESCAPE 'x' ORDER BY +y
+} {/SEARCH/}
+do_execsql_test like-15.120 {
+ SELECT y FROM t15 WHERE x LIKE '/%bc%' ESCAPE '/';
+} {22}
+do_execsql_test like-15.121 {
+ EXPLAIN QUERY PLAN
+ SELECT y FROM t15 WHERE x LIKE '/%bc%' ESCAPE '/';
+} {/SEARCH/}
+}
+
finish_test
diff --git a/third_party/sqlite/src/test/lookaside.test b/third_party/sqlite/src/test/lookaside.test
index 5a57b62..871e10f 100644
--- a/third_party/sqlite/src/test/lookaside.test
+++ b/third_party/sqlite/src/test/lookaside.test
@@ -33,7 +33,6 @@ test_set_config_pagecache 0 0
catch {db close}
sqlite3_shutdown
-sqlite3_config_scratch 0 0
sqlite3_initialize
autoinstall_test_functions
sqlite3 db test.db
diff --git a/third_party/sqlite/src/test/memsubsys1.test b/third_party/sqlite/src/test/memsubsys1.test
index 36427f9..41bc115 100644
--- a/third_party/sqlite/src/test/memsubsys1.test
+++ b/third_party/sqlite/src/test/memsubsys1.test
@@ -16,7 +16,7 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl
sqlite3_reset_auto_extension
-# This test assumes that no page-cache or scratch buffers are installed
+# This test assumes that no page-cache buffers are installed
# by default when a new database connection is opened. As a result, it
# will not work with the "memsubsys1" permutation.
#
@@ -156,12 +156,11 @@ do_test memsubsys1-3.2.5 {
set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
} 0
-# Test 4: Activate both PAGECACHE and SCRATCH.
+# Test 4: Activate PAGECACHE
#
db close
sqlite3_shutdown
sqlite3_config_pagecache [expr 1024+$xtra_size] 50
-sqlite3_config_scratch 6000 2
sqlite3_initialize
reset_highwater_marks
build_test_db memsubsys1-4 {PRAGMA page_size=1024}
@@ -177,144 +176,10 @@ do_test memsubsys1-4.5 {
set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
expr {$maxreq<7000}
} 1
-do_test memsubsys1-4.6 {
- set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
-} 1
-
-# Test 5: Activate both PAGECACHE and SCRATCH. But make the page size is
-# such that the SCRATCH allocations are too small.
-#
-db close
-sqlite3_shutdown
-sqlite3_config_pagecache [expr 4096+$xtra_size] 24
-sqlite3_config_scratch 4000 2
-sqlite3_initialize
-reset_highwater_marks
-build_test_db memsubsys1-5 {PRAGMA page_size=4096}
-#show_memstats
-do_test memsubsys1-5.3 {
- set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
-} {/^2[34]$/}
-do_test memsubsys1-5.4 {
- set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
- expr {$maxreq>4096}
-} 1
-do_test memsubsys1-5.5 {
- set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
-} 0
-do_test memsubsys1-5.6 {
- set s_ovfl [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]
- expr {$s_ovfl>6000}
-} 1
-
-# Test 6: Activate both PAGECACHE and SCRATCH with a 4k page size.
-# Make it so that SCRATCH is large enough
-#
-db close
-sqlite3_shutdown
-sqlite3_config_pagecache [expr 4096+$xtra_size] 24
-sqlite3_config_scratch 25300 1
-sqlite3_initialize
-reset_highwater_marks
-build_test_db memsubsys1-6 {PRAGMA page_size=4096}
-#show_memstats
-do_test memsubsys1-6.3 {
- set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
-} {/^2[34]$/}
-#do_test memsubsys1-6.4 {
-# set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
-# expr {$maxreq>4096 && $maxreq<=(4096+$xtra_size)}
-#} 1
-do_test memsubsys1-6.5 {
- set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
-} 1
-do_test memsubsys1-6.6 {
- set s_ovfl [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]
-} 0
-
-# Test 7: Activate both PAGECACHE and SCRATCH with a 4k page size.
-# Set cache_size small so that no PAGECACHE overflow occurs. Verify
-# that maximum allocation size is small.
-#
-db close
-sqlite3_shutdown
-sqlite3_config_pagecache [expr 4096+$xtra_size] 24
-sqlite3_config_scratch 25300 1
-sqlite3_initialize
-reset_highwater_marks
-build_test_db memsubsys1-7 {
- PRAGMA page_size=4096;
- PRAGMA cache_size=10;
- PRAGMA temp_store=memory;
-}
-#show_memstats
-do_test memsubsys1-7.3 {
- set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
- expr {$pg_used<24}
-} 1
-do_test memsubsys1-7.4 {
- set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
-} 0
-do_test memsubsys1-7.5 {
- set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
- expr {$maxreq<(4100 + 8200*[nonzero_reserved_bytes])}
-} 1
-do_test memsubsys1-7.6 {
- set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
-} 1
-do_test memsubsys1-7.7 {
- set s_ovfl [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]
-} 0
-
-# Test 8: Disable PAGECACHE. Make available SCRATCH zero. Verify that
-# the SCRATCH overflow logic works.
-#
-db close
-sqlite3_shutdown
-sqlite3_config_pagecache 0 0
-sqlite3_config_scratch 25000 0
-sqlite3_initialize
-reset_highwater_marks
-do_test memsubsys1-8.1 {
- set pg_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
-} 0
-do_test memsubsys1-8.2 {
- set s_ovfl [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]
-} 0
-do_test memsubsys1-8.3 {
- sqlite3 db :memory:
- db eval {
- CREATE TABLE t1(x);
- INSERT INTO t1 VALUES(zeroblob(400));
- INSERT INTO t1 VALUES(zeroblob(400));
- INSERT INTO t1 SELECT * FROM t1;
- INSERT INTO t1 SELECT * FROM t1;
- INSERT INTO t1 SELECT * FROM t1;
- }
- expr {[lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]>0}
-} 1
-db close
-sqlite3_shutdown
-sqlite3_config_memstatus 0
-sqlite3_initialize
-do_test memsubsys1-8.4 {
- sqlite3 db :memory:
- db eval {
- CREATE TABLE t1(x);
- INSERT INTO t1 VALUES(zeroblob(400));
- INSERT INTO t1 VALUES(zeroblob(400));
- INSERT INTO t1 SELECT * FROM t1;
- INSERT INTO t1 SELECT * FROM t1;
- INSERT INTO t1 SELECT * FROM t1;
- SELECT rowid FROM t1;
- }
-} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
-
db close
sqlite3_shutdown
sqlite3_config_memstatus 1
-sqlite3_config_scratch 0 0
sqlite3_config_lookaside 100 500
sqlite3_config serialized
sqlite3_initialize
diff --git a/third_party/sqlite/src/test/misc1.test b/third_party/sqlite/src/test/misc1.test
index 45165f9..a29e019 100644
--- a/third_party/sqlite/src/test/misc1.test
+++ b/third_party/sqlite/src/test/misc1.test
@@ -479,26 +479,28 @@ ifcapable curdir {
# Make sure a database connection still works after changing the
# working directory.
#
-do_test misc1-14.1 {
- file mkdir tempdir
- cd tempdir
- execsql {BEGIN}
- file exists ./test.db-journal
-} {0}
-do_test misc1-14.2a {
- execsql {UPDATE t1 SET a=a||'x' WHERE 0}
- file exists ../test.db-journal
-} {0}
-do_test misc1-14.2b {
- execsql {UPDATE t1 SET a=a||'y' WHERE 1}
- file exists ../test.db-journal
-} {1}
-do_test misc1-14.3 {
- cd ..
- forcedelete tempdir
- execsql {COMMIT}
- file exists ./test.db-journal
-} {0}
+if {[atomic_batch_write test.db]==0} {
+ do_test misc1-14.1 {
+ file mkdir tempdir
+ cd tempdir
+ execsql {BEGIN}
+ file exists ./test.db-journal
+ } {0}
+ do_test misc1-14.2a {
+ execsql {UPDATE t1 SET a=a||'x' WHERE 0}
+ file exists ../test.db-journal
+ } {0}
+ do_test misc1-14.2b {
+ execsql {UPDATE t1 SET a=a||'y' WHERE 1}
+ file exists ../test.db-journal
+ } {1}
+ do_test misc1-14.3 {
+ cd ..
+ forcedelete tempdir
+ execsql {COMMIT}
+ file exists ./test.db-journal
+ } {0}
+}
}
# A failed create table should not leave the table in the internal
@@ -709,5 +711,15 @@ SELECT-1 UNION SELECT 5 UNION SELECT 0 UNION SElECT*from(SELECT-5) UNION SELECT
$group,:conc ap0,1)fro,(select"",:PBAG,c,a,b,b,c,a,b,c,e,d,d,c,a,b,b,c,d,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,b,c,e,d,d,c,a,b,b,c,d,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,b,c,e,d,d,c,a,b,b,c,d,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,c,d,c,c,a,a,b,d,d,c,a,b,b,c,d,c,a,b,e,e,d,b,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d, foreign_keysc,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,a,b,d,d,c,a,b,b,c,d,c,a,b,e,e,d,b,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,b,c,e,d,d,c,a,b,b,c,d,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,c,d,c,a,b,d,d,c,a,a,b,d,d,c,a,b,b,c,d,c,a,b,e,e,d,b,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,a,b,d,d,c,a,b,b,c,d,c,a,b,e,e,d,b,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,bb,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,b,c,e,d,d,c,a,b,b,c,d,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,c,d,c,a,b,d,d,c,a,a,b,d,d,c,a,b,b,c,d,c,a,b,e,e,d,b,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,MAato_aecSELEC,+?b," "O,"i","a",""b ,5 ))KEY)SELECT*FROM((k()reaC,k,K) eA,k '' )t ,K M);
} {1 {'k' is not a function}}
+# 2017-09-17
+#
+# Sometimes sqlite3ExprListAppend() can be invoked on an ExprList that
+# was obtained from sqlite3ExprListDup().
+#
+do_execsql_test misc1-26.0 {
+ DROP TABLE IF EXISTS abc;
+ CREATE TABLE abc(a, b, c);
+ SELECT randomblob(min(max(coalesce(EXISTS (SELECT 1 FROM ( SELECT (SELECT 2147483647) NOT IN (SELECT 2147483649 UNION ALL SELECT DISTINCT -1) IN (SELECT 2147483649), 'fault', (SELECT ALL -1 INTERSECT SELECT 'experiments') IN (SELECT ALL 56.1 ORDER BY 'experiments' DESC) FROM (SELECT DISTINCT 2147483648, 'hardware' UNION ALL SELECT -2147483648, 'experiments' ORDER BY 2147483648 LIMIT 1 OFFSET 123456789.1234567899) GROUP BY (SELECT ALL 0 INTERSECT SELECT 'in') IN (SELECT DISTINCT 'experiments' ORDER BY zeroblob(1000) LIMIT 56.1 OFFSET -456) HAVING EXISTS (SELECT 'fault' EXCEPT SELECT DISTINCT 56.1) UNION SELECT 'The', 'The', 2147483649 UNION ALL SELECT DISTINCT 'hardware', 'first', 'experiments' ORDER BY 'hardware' LIMIT 123456789.1234567899 OFFSET -2147483647)) NOT IN (SELECT (SELECT DISTINCT (SELECT 'The') FROM abc ORDER BY EXISTS (SELECT -1 INTERSECT SELECT ALL NULL) ASC) IN (SELECT DISTINCT EXISTS (SELECT ALL 123456789.1234567899 ORDER BY 1 ASC, NULL DESC) FROM sqlite_master INTERSECT SELECT 456)), (SELECT ALL 'injection' UNION ALL SELECT ALL (SELECT DISTINCT 'first' UNION SELECT DISTINCT 'The') FROM (SELECT 456, 'in', 2147483649))),1), 500)), 'first', EXISTS (SELECT DISTINCT 456 FROM abc ORDER BY 'experiments' DESC) FROM abc;
+} {}
finish_test
diff --git a/third_party/sqlite/src/test/mjournal.test b/third_party/sqlite/src/test/mjournal.test
new file mode 100644
index 0000000..7da0307
--- /dev/null
+++ b/third_party/sqlite/src/test/mjournal.test
@@ -0,0 +1,83 @@
+# 2017 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 file implements regression tests for SQLite library.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix mjournal
+
+# Test that nothing bad happens if a journal file contains a pointer to
+# a master journal file that does not have a "-" in the name. At one point
+# this was causing a segfault on unix.
+#
+do_execsql_test 1.0 {
+ CREATE TABLE t1(a, b);
+}
+
+do_test 1.1 {
+ forcedelete test.db2journal test.db-journal
+
+ close [open test.db-journal w]
+
+ hexio_write test.db-journal 0 746573742e6462326a6f75726e616c00
+ hexio_write test.db-journal 16 00000010
+ hexio_write test.db-journal 20 000005e1
+ hexio_write test.db-journal 24 d9d505f920a163d7
+
+ close [open test.db2journal w]
+ hexio_write test.db2journal 0 abcd
+} {2}
+
+do_execsql_test 1.2 {
+ SELECT * FROM t1;
+}
+
+do_test 1.3 {
+ forcedelete test0db2journal test.db-journal
+ close [open test.db-journal w]
+ hexio_write test.db-journal 0 74657374306462326a6f75726e616c00
+ hexio_write test.db-journal 16 00000010
+ hexio_write test.db-journal 20 000005e3
+ hexio_write test.db-journal 24 d9d505f920a163d7
+
+ close [open test0db2journal w]
+ hexio_write test0db2journal 0 abcd
+} {2}
+
+do_execsql_test 1.4 {
+ SELECT * FROM t1;
+}
+
+# And now test that nothing bad happens if a master journal contains a
+# pointer to a journal file that does not have a "-" in the name.
+#
+do_test 1.5 {
+ forcedelete test.db2-master test.db-journal test1
+ close [open test.db-journal w]
+ hexio_write test.db-journal 0 746573742e6462322d6d617374657200
+ hexio_write test.db-journal 16 00000010
+ hexio_write test.db-journal 20 0000059f
+ hexio_write test.db-journal 24 d9d505f920a163d7
+
+ close [open test.db2-master w]
+ hexio_write test.db2-master 0 746573743100
+
+ close [open test1 w]
+ hexio_write test1 0 abcd
+} {2}
+
+do_execsql_test 1.6 {
+ SELECT * FROM t1;
+}
+
+
+finish_test
diff --git a/third_party/sqlite/src/test/mmapwarm.test b/third_party/sqlite/src/test/mmapwarm.test
new file mode 100644
index 0000000..f3fb0a5
--- /dev/null
+++ b/third_party/sqlite/src/test/mmapwarm.test
@@ -0,0 +1,81 @@
+# 20 September 18
+#
+# 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.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+
+if 0 {
+ db close
+ sqlite3_shutdown
+ proc msg {args} { puts $args }
+ test_sqlite3_log msg
+ sqlite3 db test.db
+}
+
+set testprefix mmapwarm
+
+
+do_execsql_test 1.0 {
+ PRAGMA auto_vacuum = 0;
+ CREATE TABLE t1(x, y);
+ WITH s(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500
+ )
+ INSERT INTO t1 SELECT randomblob(400), randomblob(500) FROM s;
+ PRAGMA page_count;
+} {507}
+db close
+
+do_test 1.1 {
+ sqlite3 db test.db
+ db eval {PRAGMA mmap_size = 1000000}
+ sqlite3_mmap_warm db
+} {SQLITE_OK}
+
+do_test 1.2 {
+ db close
+ sqlite3 db test.db
+ db eval {PRAGMA mmap_size = 1000000}
+ sqlite3_mmap_warm db "main"
+} {SQLITE_OK}
+
+do_test 1.3 {
+ sqlite3 db test.db
+ sqlite3_mmap_warm db
+} {SQLITE_OK}
+
+do_test 1.4 {
+ db close
+ sqlite3 db test.db
+ sqlite3_mmap_warm db "main"
+} {SQLITE_OK}
+
+do_test 2.0 {
+ db close
+ sqlite3 db test.db
+ db eval BEGIN
+ sqlite3_mmap_warm db "main"
+} {SQLITE_MISUSE}
+
+do_faultsim_test 3 -faults oom* -prep {
+ sqlite3 db test.db
+ sqlite3_db_config_lookaside db 0 0 0
+ db eval { PRAGMA mmap_size = 1000000 }
+ db eval { SELECT * FROM sqlite_master }
+} -body {
+ sqlite3_mmap_warm db "main"
+} -test {
+ faultsim_test_result {0 SQLITE_OK} {0 SQLITE_NOMEM}
+}
+
+finish_test
diff --git a/third_party/sqlite/src/test/nan.test b/third_party/sqlite/src/test/nan.test
index e1fe078..67bab57 100644
--- a/third_party/sqlite/src/test/nan.test
+++ b/third_party/sqlite/src/test/nan.test
@@ -366,8 +366,10 @@ do_realnum_test nan-4.35 {
}
} {0.0 real}
-
-
-
+do_realnum_test nan-4.40 {
+ db eval {
+ SELECT cast('-1e999' AS real);
+ }
+} {-inf}
finish_test
diff --git a/third_party/sqlite/src/test/ossfuzz.c b/third_party/sqlite/src/test/ossfuzz.c
index 5198354..7b28cf6 100644
--- a/third_party/sqlite/src/test/ossfuzz.c
+++ b/third_party/sqlite/src/test/ossfuzz.c
@@ -71,6 +71,28 @@ static int progress_handler(void *pClientData) {
#endif
/*
+** Disallow debugging pragmas such as "PRAGMA vdbe_debug" and
+** "PRAGMA parser_trace" since they can dramatically increase the
+** amount of output without actually testing anything useful.
+*/
+static int block_debug_pragmas(
+ void *Notused,
+ int eCode,
+ const char *zArg1,
+ const char *zArg2,
+ const char *zArg3,
+ const char *zArg4
+){
+ if( eCode==SQLITE_PRAGMA
+ && (sqlite3_strnicmp("vdbe_", zArg1, 5)==0
+ || sqlite3_stricmp("parser_trace", zArg1)==0)
+ ){
+ return SQLITE_DENY;
+ }
+ return SQLITE_OK;
+}
+
+/*
** Callback for sqlite3_exec().
*/
static int exec_handler(void *pCnt, int argc, char **argv, char **namev){
@@ -128,6 +150,9 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
sqlite3_db_config(cx.db, SQLITE_DBCONFIG_ENABLE_FKEY, uSelector&1, &rc);
uSelector >>= 1;
+ /* Do not allow debugging pragma statements that might cause excess output */
+ sqlite3_set_authorizer(cx.db, block_debug_pragmas, 0);
+
/* Remaining bits of the selector determine a limit on the number of
** output rows */
execCnt = uSelector + 1;
diff --git a/third_party/sqlite/src/test/permutations.test b/third_party/sqlite/src/test/permutations.test
index edcc8e1..4a49a9e 100644
--- a/third_party/sqlite/src/test/permutations.test
+++ b/third_party/sqlite/src/test/permutations.test
@@ -194,7 +194,7 @@ test_suite "valgrind" -prefix "" -description {
} -files [
test_set $allquicktests -exclude *malloc* *ioerr* *fault* *_err* wal.test \
shell*.test crash8.test atof1.test selectG.test \
- tkt-fc62af4523.test numindex1.test
+ tkt-fc62af4523.test numindex1.test corruptK.test
] -initialize {
set ::G(valgrind) 1
} -shutdown {
@@ -389,6 +389,30 @@ test_suite "vfslog" -prefix "" -description {
wal* mmap*
]
+test_suite "atomic-batch-write" -prefix "" -description {
+ Like veryquick.test, but must be run on a file-system that supports
+ atomic-batch-writes. Tests that depend on the journal file being present
+ are omitted.
+} -files [
+ test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* *_err* \
+ *fts5corrupt* *fts5big* *fts5aj* \
+ crash8.test delete_db.test \
+ exclusive.test journal3.test \
+ journal1.test \
+ jrnlmode.test jrnlmode2.test \
+ lock4.test pager1.test \
+ pager3.test sharedA.test \
+ symlink.test stmt.test \
+ sync.test sync2.test \
+ tempdb.test tkt3457.test \
+ vacuum5.test wal2.test \
+ walmode.test zerodamage.test
+] -initialize {
+ if {[atomic_batch_write test.db]==0} {
+ error "File system does NOT support atomic-batch-write"
+ }
+}
+
lappend ::testsuitelist xxx
#-------------------------------------------------------------------------
# Define the coverage related test suites:
@@ -431,33 +455,31 @@ lappend ::testsuitelist xxx
# Define the permutation test suites:
#
-# Run some tests using pre-allocated page and scratch blocks.
+# Run some tests using pre-allocated page blocks.
#
# mmap1.test is excluded because a good number of its tests depend on
# the page-cache being larger than the database. But this permutation
# causes the effective limit on the page-cache to be just 24 pages.
#
test_suite "memsubsys1" -description {
- Tests using pre-allocated page and scratch blocks
+ Tests using pre-allocated page blocks
} -files [
test_set $::allquicktests -exclude ioerr5.test malloc5.test mmap1.test
] -initialize {
test_set_config_pagecache 4096 24
catch {db close}
sqlite3_shutdown
- sqlite3_config_scratch 25000 1
sqlite3_initialize
autoinstall_test_functions
} -shutdown {
test_restore_config_pagecache
catch {db close}
sqlite3_shutdown
- sqlite3_config_scratch 0 0
sqlite3_initialize
autoinstall_test_functions
}
-# Run some tests using pre-allocated page and scratch blocks. This time
+# Run some tests using pre-allocated page blocks. This time
# the allocations are too small to use in most cases.
#
# Both ioerr5.test and malloc5.test are excluded because they test the
@@ -465,21 +487,19 @@ test_suite "memsubsys1" -description {
# This functionality is disabled if a pre-allocated page block is provided.
#
test_suite "memsubsys2" -description {
- Tests using small pre-allocated page and scratch blocks
+ Tests using small pre-allocated page blocks
} -files [
test_set $::allquicktests -exclude ioerr5.test malloc5.test
] -initialize {
test_set_config_pagecache 512 5
catch {db close}
sqlite3_shutdown
- sqlite3_config_scratch 1000 1
sqlite3_initialize
autoinstall_test_functions
} -shutdown {
test_restore_config_pagecache
catch {db close}
sqlite3_shutdown
- sqlite3_config_scratch 0 0
sqlite3_initialize
autoinstall_test_functions
}
@@ -1045,7 +1065,7 @@ test_suite "no_optimization" -description {
test_suite "prepare" -description {
Run tests with the db connection using sqlite3_prepare() instead of _v2().
} -dbconfig {
- db_use_legacy_prepare $::dbhandle 1
+ $::dbhandle version -use-legacy-prepare 1
#$::dbhandle cache size 0
} -files [
test_set $allquicktests -exclude *malloc* *ioerr* *fault* \
diff --git a/third_party/sqlite/src/test/pragma.test b/third_party/sqlite/src/test/pragma.test
index 2959ff7..0b9ca29 100644
--- a/third_party/sqlite/src/test/pragma.test
+++ b/third_party/sqlite/src/test/pragma.test
@@ -1932,6 +1932,29 @@ do_test 23.5 {
PRAGMA foreign_key_list(t2);
}
} {0 0 t1 y {} {NO ACTION} {NO ACTION} NONE}
+db2 close
+
+ifcapable !has_codec {
+ reset_db
+ do_execsql_test 24.0 {
+ PRAGMA page_size = 1024;
+ CREATE TABLE t1(a, b, c);
+ CREATE INDEX i1 ON t1(b);
+ INSERT INTO t1 VALUES('a', 'b', 'c');
+ PRAGMA integrity_check;
+ } {ok}
+
+ set r [db one {SELECT rootpage FROM sqlite_master WHERE name = 't1'}]
+ db close
+ hexio_write test.db [expr $r*1024 - 16] 000000000000000701040f0f1f616263
+ sqlite3 db test.db
+ do_catchsql_test 24.1 {
+ SELECT * FROM t1;
+ } {1 {database disk image is malformed}}
+ do_catchsql_test 24.2 {
+ PRAGMA integrity_check;
+ } {0 {{database disk image is malformed}}}
+}
database_never_corrupt
finish_test
diff --git a/third_party/sqlite/src/test/pragma5.test b/third_party/sqlite/src/test/pragma5.test
new file mode 100644
index 0000000..fd6fdf5
--- /dev/null
+++ b/third_party/sqlite/src/test/pragma5.test
@@ -0,0 +1,64 @@
+# 2017 August 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 implements regression tests for SQLite library.
+#
+# This file implements tests for the PRAGMA command. Specifically,
+# those pragmas enabled at build time by setting:
+#
+# -DSQLITE_INTROSPECTION_PRAGMAS
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix pragma5
+
+if { [catch {db one "SELECT count(*) FROM pragma_function_list"}] } {
+ finish_test
+ return
+}
+
+db function external external
+
+do_execsql_test 1.0 {
+ PRAGMA table_info(pragma_function_list)
+} {
+ 0 name {} 0 {} 0
+ 1 builtin {} 0 {} 0
+}
+do_execsql_test 1.1 {
+ SELECT * FROM pragma_function_list WHERE name='upper'
+} {upper 1}
+do_execsql_test 1.2 {
+ SELECT * FROM pragma_function_list WHERE name LIKE 'exter%';
+} {external 0}
+
+ifcapable fts5 {
+ do_execsql_test 2.0 {
+ PRAGMA table_info(pragma_module_list)
+ } {
+ 0 name {} 0 {} 0
+ }
+ do_execsql_test 2.1 {
+ SELECT * FROM pragma_module_list WHERE name='fts5'
+ } {fts5}
+}
+
+do_execsql_test 3.0 {
+ PRAGMA table_info(pragma_pragma_list)
+} {
+ 0 name {} 0 {} 0
+}
+do_execsql_test 3.1 {
+ SELECT * FROM pragma_pragma_list WHERE name='pragma_list'
+} {pragma_list}
+
+
+finish_test
diff --git a/third_party/sqlite/src/test/releasetest.tcl b/third_party/sqlite/src/test/releasetest.tcl
index 3689b71..2539d20 100755
--- a/third_party/sqlite/src/test/releasetest.tcl
+++ b/third_party/sqlite/src/test/releasetest.tcl
@@ -114,7 +114,7 @@ array set ::Configs [strip_comments {
}
"Debug-One" {
--disable-shared
- -O2
+ -O2 -funsigned-char
-DSQLITE_DEBUG=1
-DSQLITE_MEMDEBUG=1
-DSQLITE_MUTEX_NOOP=1
@@ -126,6 +126,7 @@ array set ::Configs [strip_comments {
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_HIDDEN_COLUMNS
-DSQLITE_MAX_ATTACHED=125
+ -DSQLITE_MUTATION_TEST
}
"Fast-One" {
-O6
diff --git a/third_party/sqlite/src/test/rollback.test b/third_party/sqlite/src/test/rollback.test
index 9cf99e6..bbc80de 100644
--- a/third_party/sqlite/src/test/rollback.test
+++ b/third_party/sqlite/src/test/rollback.test
@@ -82,6 +82,7 @@ do_test rollback-1.9 {
if {$tcl_platform(platform) == "unix"
&& [permutation] ne "onefile"
&& [permutation] ne "inmemory_journal"
+ && [permutation] ne "atomic-batch-write"
} {
do_test rollback-2.1 {
execsql {
diff --git a/third_party/sqlite/src/test/savepoint.test b/third_party/sqlite/src/test/savepoint.test
index d05b50a..bfd2c8c 100644
--- a/third_party/sqlite/src/test/savepoint.test
+++ b/third_party/sqlite/src/test/savepoint.test
@@ -616,12 +616,16 @@ ifcapable auth {
# First make sure it is not possible to attach or detach a database while
# a savepoint is open (it is not possible if any transaction is open).
#
+# UPDATE 2017-07-26: It is not possible to ATTACH and DETACH within a
+# a transaction.
+#
do_test savepoint-10.1.1 {
catchsql {
SAVEPOINT one;
ATTACH 'test2.db' AS aux;
+ DETACH aux;
}
-} {1 {cannot ATTACH database within transaction}}
+} {0 {}}
do_test savepoint-10.1.2 {
execsql {
RELEASE one;
@@ -630,8 +634,9 @@ do_test savepoint-10.1.2 {
catchsql {
SAVEPOINT one;
DETACH aux;
+ ATTACH 'test2.db' AS aux;
}
-} {1 {cannot DETACH database within transaction}}
+} {0 {}}
do_test savepoint-10.1.3 {
execsql {
RELEASE one;
diff --git a/third_party/sqlite/src/test/scanstatus.test b/third_party/sqlite/src/test/scanstatus.test
index 4fbb057..cbaa396 100644
--- a/third_party/sqlite/src/test/scanstatus.test
+++ b/third_party/sqlite/src/test/scanstatus.test
@@ -30,7 +30,7 @@ do_execsql_test 1.0 {
}
proc do_scanstatus_test {tn res} {
- set stmt [db_last_stmt_ptr db]
+ set stmt [db version -last-stmt-ptr]
set idx 0
set ret [list]
while {1} {
@@ -79,7 +79,7 @@ do_scanstatus_test 1.9 {
}
do_test 1.9 {
- sqlite3_stmt_scanstatus_reset [db_last_stmt_ptr db]
+ sqlite3_stmt_scanstatus_reset [db version -last-stmt-ptr]
} {}
do_scanstatus_test 1.10 {
diff --git a/third_party/sqlite/src/test/schema6.test b/third_party/sqlite/src/test/schema6.test
new file mode 100644
index 0000000..2a0fbfd
--- /dev/null
+++ b/third_party/sqlite/src/test/schema6.test
@@ -0,0 +1,164 @@
+# 2017-07-30
+#
+# 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 tests to show that certain CREATE TABLE statements
+# generate identical database files. For example, changes in identifier
+# names, white-space, and formatting of the CREATE TABLE statement should
+# produce identical table content.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set ::testprefix schema6
+do_not_use_codec
+
+# Command: check_same_database_content TESTNAME SQL1 SQL2 SQL3 ...
+#
+# This command creates fresh databases using SQL1 and subsequent arguments
+# and checks to make sure the content of all database files is byte-for-byte
+# identical. Page 1 of the database files is allowed to be different, since
+# page 1 contains the sqlite_master table which is expected to vary.
+#
+proc check_same_database_content {basename args} {
+ set i 0
+ set hash {}
+ foreach sql $args {
+ catch {db close}
+ forcedelete test.db
+ sqlite3 db test.db
+ db eval $sql
+ set pgsz [db one {PRAGMA page_size}]
+ db close
+ set sz [file size test.db]
+ set thishash [md5file test.db $pgsz [expr {$sz-$pgsz}]]
+ if {$i==0} {
+ set hash $thishash
+ } else {
+ do_test $basename-$i "set x $thishash" $hash
+ }
+ incr i
+ }
+}
+
+# Command: check_different_database_content TESTNAME SQL1 SQL2 SQL3 ...
+#
+# This command creates fresh databases using SQL1 and subsequent arguments
+# and checks to make sure the content of all database files is different
+# in ways other than on page 1.
+#
+proc check_different_database_content {basename args} {
+ set i 0
+ set hashes {}
+ foreach sql $args {
+ forcedelete test.db
+ sqlite3 db test.db
+ db eval $sql
+ set pgsz [db one {PRAGMA page_size}]
+ db close
+ set sz [file size test.db]
+ set thishash [md5file test.db $pgsz [expr {$sz-$pgsz}]]
+ set j [lsearch $hashes $thishash]
+ if {$j>=0} {
+ do_test $basename-$i "set x {$i is the same as $j}" "All are different"
+ } else {
+ do_test $basename-$i "set x {All are different}" "All are different"
+ }
+ lappend hashes $thishash
+ incr i
+ }
+}
+
+check_same_database_content 100 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(xyz INTEGER, abc, PRIMARY KEY(xyz), UNIQUE(abc));
+ INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(xyz INTEGER, abc, UNIQUE(abc), PRIMARY KEY(xyz));
+ INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY ASC, b UNIQUE);
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+ CREATE UNIQUE INDEX t1b ON t1(b);
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+ CREATE UNIQUE INDEX t1b ON t1(b);
+}
+
+check_same_database_content 110 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY UNIQUE, b UNIQUE);
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE);
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE, UNIQUE(a));
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b);
+ CREATE UNIQUE INDEX t1b ON t1(b);
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b);
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+ CREATE UNIQUE INDEX t1b ON t1(b);
+}
+
+check_same_database_content 120 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE) WITHOUT ROWID;
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(xyz INTEGER, abc, PRIMARY KEY(xyz), UNIQUE(abc))WITHOUT ROWID;
+ INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(xyz INTEGER, abc, UNIQUE(abc), PRIMARY KEY(xyz))WITHOUT ROWID;
+ INSERT INTO t1(xyz,abc) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY ASC, b UNIQUE) WITHOUT ROWID;
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY UNIQUE, b UNIQUE) WITHOUT ROWID;
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE) WITHOUT ROWID;
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER UNIQUE PRIMARY KEY, b UNIQUE, UNIQUE(a))
+ WITHOUT ROWID;
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b) WITHOUT ROWID;
+ CREATE UNIQUE INDEX t1b ON t1(b);
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b) WITHOUT ROWID;
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+ CREATE UNIQUE INDEX t1b ON t1(b);
+}
+
+check_different_database_content 130 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE);
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY UNIQUE, b UNIQUE);
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+} {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE) WITHOUT ROWID;
+ INSERT INTO t1(a,b) VALUES(123,'Four score and seven years ago...');
+}
+
+
+finish_test
diff --git a/third_party/sqlite/src/test/select1.test b/third_party/sqlite/src/test/select1.test
index 09ed84c..f44d384 100644
--- a/third_party/sqlite/src/test/select1.test
+++ b/third_party/sqlite/src/test/select1.test
@@ -545,9 +545,9 @@ do_test select1-6.9.7 {
set x [execsql2 {
SELECT * FROM test1 a, (select 5, 6) LIMIT 1
}]
- regsub -all {sq_[0-9a-fA-F_]+} $x {subquery} x
+ regsub -all {subquery_[0-9a-fA-F_]+} $x {subquery} x
set x
-} {a.f1 11 a.f2 22 sqlite_subquery.5 5 sqlite_subquery.6 6}
+} {a.f1 11 a.f2 22 subquery.5 5 subquery.6 6}
do_test select1-6.9.8 {
set x [execsql2 {
SELECT * FROM test1 a, (select 5 AS x, 6 AS y) AS b LIMIT 1
diff --git a/third_party/sqlite/src/test/snapshot2.test b/third_party/sqlite/src/test/snapshot2.test
index 41e5552..8403cdb 100644
--- a/third_party/sqlite/src/test/snapshot2.test
+++ b/third_party/sqlite/src/test/snapshot2.test
@@ -197,4 +197,45 @@ do_test 4.7 {
list [catch { sqlite3_snapshot_recover db aux } msg] $msg
} {1 SQLITE_ERROR}
+#-------------------------------------------------------------------------
+reset_db
+sqlite3 db2 test.db
+do_execsql_test 5.0 {
+ CREATE TABLE t2(x);
+ PRAGMA journal_mode = wal;
+ INSERT INTO t2 VALUES('abc');
+ INSERT INTO t2 VALUES('def');
+ INSERT INTO t2 VALUES('ghi');
+} {wal}
+
+do_test 5.1 {
+ execsql {
+ SELECT * FROM t2;
+ BEGIN;
+ } db2
+ set snap [sqlite3_snapshot_get_blob db2 main]
+ db2 eval END
+} {}
+
+do_test 5.2 {
+ execsql BEGIN db2
+ sqlite3_snapshot_open_blob db2 main $snap
+ db2 eval { SELECT * FROM t2 ; END }
+} {abc def ghi}
+
+do_test 5.3 {
+ execsql { PRAGMA wal_checkpoint = RESTART }
+ execsql BEGIN db2
+ sqlite3_snapshot_open_blob db2 main $snap
+ db2 eval { SELECT * FROM t2 ; END }
+} {abc def ghi}
+
+do_test 5.4 {
+ execsql { INSERT INTO t2 VALUES('jkl') }
+ execsql BEGIN db2
+ list [catch { sqlite3_snapshot_open_blob db2 main $snap } msg] $msg
+} {1 SQLITE_BUSY_SNAPSHOT}
+
+
finish_test
+
diff --git a/third_party/sqlite/src/test/speedtest1.c b/third_party/sqlite/src/test/speedtest1.c
index 1bb7219..29acacc 100644
--- a/third_party/sqlite/src/test/speedtest1.c
+++ b/third_party/sqlite/src/test/speedtest1.c
@@ -25,7 +25,6 @@ static const char zHelp[] =
" --primarykey Use PRIMARY KEY instead of UNIQUE where appropriate\n"
" --repeat N Repeat each SELECT N times (default: 1)\n"
" --reprepare Reprepare each statement upon every invocation\n"
- " --scratch N SZ Configure scratch memory for N slots of SZ bytes each\n"
" --serialized Set serialized threading mode\n"
" --singlethread Set single-threaded mode - disables all mutexing\n"
" --sqlonly No-op. Only show the SQL that would have been run.\n"
@@ -1636,6 +1635,11 @@ static void displayLinuxIoStats(FILE *out){
# define sqlite3_sourceid(X) "(before 3.6.18)"
#endif
+static int xCompileOptions(void *pCtx, int nVal, char **azVal, char **azCol){
+ printf("-- Compile option: %s\n", azVal[0]);
+ return SQLITE_OK;
+}
+
int main(int argc, char **argv){
int doAutovac = 0; /* True for --autovacuum */
int cacheSize = 0; /* Desired cache size. 0 means default */
@@ -1649,7 +1653,6 @@ int main(int argc, char **argv){
int pageSize = 0; /* Desired page size. 0 means default */
int nPCache = 0, szPCache = 0;/* --pcache configuration */
int doPCache = 0; /* True if --pcache is seen */
- int nScratch = 0, szScratch=0;/* --scratch configuration */
int showStats = 0; /* True for --stats */
int nThread = 0; /* --threads value */
int mmapSize = 0; /* How big of a memory map to use */
@@ -1661,7 +1664,6 @@ int main(int argc, char **argv){
void *pHeap = 0; /* Allocated heap space */
void *pLook = 0; /* Allocated lookaside space */
void *pPCache = 0; /* Allocated storage for pcache */
- void *pScratch = 0; /* Allocated storage for scratch */
int iCur, iHi; /* Stats values, current and "highwater" */
int i; /* Loop counter */
int rc; /* API return code */
@@ -1741,11 +1743,6 @@ int main(int argc, char **argv){
i += 1;
}else if( strcmp(z,"reprepare")==0 ){
g.bReprepare = 1;
- }else if( strcmp(z,"scratch")==0 ){
- if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]);
- nScratch = integerValue(argv[i+1]);
- szScratch = integerValue(argv[i+2]);
- i += 2;
#if SQLITE_VERSION_NUMBER>=3006000
}else if( strcmp(z,"serialized")==0 ){
sqlite3_config(SQLITE_CONFIG_SERIALIZED);
@@ -1816,13 +1813,6 @@ int main(int argc, char **argv){
rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache);
if( rc ) fatal_error("pcache configuration failed: %d\n", rc);
}
- if( nScratch>0 && szScratch>0 ){
- pScratch = malloc( nScratch*(sqlite3_int64)szScratch );
- if( pScratch==0 ) fatal_error("cannot allocate %lld-byte scratch\n",
- nScratch*(sqlite3_int64)szScratch);
- rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, pScratch, szScratch, nScratch);
- if( rc ) fatal_error("scratch configuration failed: %d\n", rc);
- }
if( nLook>=0 ){
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);
}
@@ -1896,6 +1886,10 @@ int main(int argc, char **argv){
}
speedtest1_final();
+ if( showStats ){
+ sqlite3_exec(g.db, "PRAGMA compile_options", xCompileOptions, 0, 0);
+ }
+
/* Database connection statistics printed after both prepared statements
** have been finalized */
#if SQLITE_VERSION_NUMBER>=3007009
@@ -1939,14 +1933,10 @@ int main(int argc, char **argv){
#endif
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHi, 0);
printf("-- Pcache Overflow Bytes: %d (max %d)\n", iCur,iHi);
- sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHi, 0);
- printf("-- Scratch Overflow Bytes: %d (max %d)\n", iCur,iHi);
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHi, 0);
printf("-- Largest Allocation: %d bytes\n",iHi);
sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHi, 0);
printf("-- Largest Pcache Allocation: %d bytes\n",iHi);
- sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHi, 0);
- printf("-- Largest Scratch Allocation: %d bytes\n", iHi);
}
#endif
@@ -1959,7 +1949,6 @@ int main(int argc, char **argv){
/* Release memory */
free( pLook );
free( pPCache );
- free( pScratch );
free( pHeap );
return 0;
}
diff --git a/third_party/sqlite/src/test/swarmvtab.test b/third_party/sqlite/src/test/swarmvtab.test
new file mode 100644
index 0000000..1dae0e0
--- /dev/null
+++ b/third_party/sqlite/src/test/swarmvtab.test
@@ -0,0 +1,246 @@
+# 2017-07-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 file implements regression tests for SQLite library. The
+# focus of this file is the "swarmvtab" extension
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix swarmvtab
+do_not_use_codec
+
+ifcapable !vtab {
+ finish_test
+ return
+}
+
+load_static_extension db unionvtab
+
+set nFile $sqlite_open_file_count
+
+do_execsql_test 1.0 {
+ CREATE TABLE t0(a INTEGER PRIMARY KEY, b TEXT);
+ WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<400)
+ INSERT INTO t0 SELECT i, hex(randomblob(50)) FROM s;
+
+ CREATE TABLE dir(f, t, imin, imax);
+}
+
+do_test 1.1 {
+ for {set i 0} {$i < 40} {incr i} {
+ set iMin [expr $i*10 + 1]
+ set iMax [expr $iMin+9]
+
+ forcedelete "test.db$i"
+ execsql [subst {
+ ATTACH 'test.db$i' AS aux;
+ CREATE TABLE aux.t$i (a INTEGER PRIMARY KEY, b TEXT);
+ INSERT INTO aux.t$i SELECT * FROM t0 WHERE a BETWEEN $iMin AND $iMax;
+ DETACH aux;
+ INSERT INTO dir VALUES('test.db$i', 't$i', $iMin, $iMax);
+ }]
+ }
+
+ execsql {
+ CREATE VIRTUAL TABLE temp.s1 USING swarmvtab('SELECT * FROM dir');
+ }
+} {}
+
+do_execsql_test 1.2 {
+ DROP TABLE s1;
+} {}
+
+do_execsql_test 1.3 {
+ CREATE VIRTUAL TABLE temp.s1 USING swarmvtab('SELECT * FROM dir');
+ SELECT count(*) FROM s1 WHERE rowid<50;
+} {49}
+
+proc do_compare_test {tn where} {
+ set sql [subst {
+ SELECT (SELECT group_concat(a || ',' || b, ',') FROM t0 WHERE $where)
+ IS
+ (SELECT group_concat(a || ',' || b, ',') FROM s1 WHERE $where)
+ }]
+
+ uplevel [list do_execsql_test $tn $sql 1]
+}
+
+do_compare_test 1.4.1 "rowid = 700"
+do_compare_test 1.4.2 "rowid = -1"
+do_compare_test 1.4.3 "rowid = 0"
+do_compare_test 1.4.4 "rowid = 55"
+do_compare_test 1.4.5 "rowid BETWEEN 20 AND 100"
+do_compare_test 1.4.6 "rowid > 350"
+do_compare_test 1.4.7 "rowid >= 350"
+do_compare_test 1.4.8 "rowid >= 200"
+do_compare_test 1.4.9 "1"
+
+# Multiple simultaneous cursors.
+#
+do_execsql_test 1.5.1.(5-seconds-or-so) {
+ SELECT count(*) FROM s1 a, s1 b WHERE b.rowid<=200;
+} {80000}
+do_execsql_test 1.5.2 {
+ SELECT count(*) FROM s1 a, s1 b, s1 c
+ WHERE a.rowid=b.rowid AND b.rowid=c.rowid;
+} {400}
+
+# Empty source tables.
+#
+do_test 1.6.0 {
+ for {set i 0} {$i < 20} {incr i} {
+ sqlite3 db2 test.db$i
+ db2 eval " DELETE FROM t$i "
+ db2 close
+ }
+ db eval { DELETE FROM t0 WHERE rowid<=200 }
+} {}
+
+do_compare_test 1.6.1 "rowid = 700"
+do_compare_test 1.6.2 "rowid = -1"
+do_compare_test 1.6.3 "rowid = 0"
+do_compare_test 1.6.4 "rowid = 55"
+do_compare_test 1.6.5 "rowid BETWEEN 20 AND 100"
+do_compare_test 1.6.6 "rowid > 350"
+do_compare_test 1.6.7 "rowid >= 350"
+do_compare_test 1.6.8 "rowid >= 200"
+do_compare_test 1.6.9 "1"
+do_compare_test 1.6.10 "rowid >= 5"
+
+do_test 1.x {
+ set sqlite_open_file_count
+} [expr $nFile+9]
+
+do_test 1.y { db close } {}
+
+# Delete all the database files created above.
+#
+for {set i 0} {$i < 40} {incr i} { forcedelete "test.db$i" }
+
+#-------------------------------------------------------------------------
+# Test some error conditions:
+#
+# 2.1: Database file does not exist.
+# 2.2: Table does not exist.
+# 2.3: Table schema does not match.
+# 2.4: Syntax error in SELECT statement.
+#
+reset_db
+load_static_extension db unionvtab
+do_test 2.0.1 {
+ db eval {
+ CREATE TABLE t0(a INTEGER PRIMARY KEY, b TEXT);
+ WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<400)
+ INSERT INTO t0 SELECT i, hex(randomblob(50)) FROM s;
+ CREATE TABLE dir(f, t, imin, imax);
+ }
+
+ for {set i 0} {$i < 40} {incr i} {
+ set iMin [expr $i*10 + 1]
+ set iMax [expr $iMin+9]
+
+ forcedelete "test.db$i"
+ db eval [subst {
+ ATTACH 'test.db$i' AS aux;
+ CREATE TABLE aux.t$i (a INTEGER PRIMARY KEY, b TEXT);
+ INSERT INTO aux.t$i SELECT * FROM t0 WHERE a BETWEEN $iMin AND $iMax;
+ DETACH aux;
+ INSERT INTO dir VALUES('test.db$i', 't$i', $iMin, $iMax);
+ }]
+ }
+ execsql {
+ CREATE VIRTUAL TABLE temp.s1 USING swarmvtab('SELECT * FROM dir');
+ }
+} {}
+
+do_test 2.0.2 {
+ forcedelete test.db5
+
+ sqlite3 db2 test.db15
+ db2 eval { DROP TABLE t15 }
+ db2 close
+
+ sqlite3 db2 test.db25
+ db2 eval {
+ DROP TABLE t25;
+ CREATE TABLE t25(x, y, z PRIMARY KEY);
+ }
+ db2 close
+} {}
+
+do_catchsql_test 2.1 {
+ SELECT * FROM s1 WHERE rowid BETWEEN 1 AND 100;
+} {1 {unable to open database file}}
+do_catchsql_test 2.2 {
+ SELECT * FROM s1 WHERE rowid BETWEEN 101 AND 200;
+} {1 {no such rowid table: t15}}
+do_catchsql_test 2.3 {
+ SELECT * FROM s1 WHERE rowid BETWEEN 201 AND 300;
+} {1 {source table schema mismatch}}
+
+do_catchsql_test 2.4 {
+ CREATE VIRTUAL TABLE temp.x1 USING swarmvtab('SELECT * FROMdir');
+} {1 {sql error: near "FROMdir": syntax error}}
+do_catchsql_test 2.5 {
+ CREATE VIRTUAL TABLE temp.x1 USING swarmvtab('SELECT * FROMdir', 'fetchdb');
+} {1 {sql error: near "FROMdir": syntax error}}
+
+for {set i 0} {$i < 40} {incr i} {
+ forcedelete "test.db$i"
+}
+
+#-------------------------------------------------------------------------
+# Test the outcome of the fetch function throwing an exception.
+#
+proc fetch_db {file} {
+ error "fetch_db error!"
+}
+
+db func fetch_db fetch_db
+
+do_catchsql_test 3.1 {
+ CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
+ 'VALUES
+ ("test.db1", "t1", 1, 10),
+ ("test.db2", "t1", 11, 20)
+ ', 'fetch_db_no_such_function'
+ );
+} {1 {no such function: fetch_db_no_such_function}}
+
+do_catchsql_test 3.2 {
+ CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
+ 'VALUES
+ ("test.db1", "t1", 1, 10),
+ ("test.db2", "t1", 11, 20)
+ ', 'fetch_db'
+ );
+} {1 {fetch_db error!}}
+
+do_execsql_test 3.3.1 {
+ ATTACH 'test.db1' AS aux;
+ CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b);
+ INSERT INTO aux.t1 VALUES(1, NULL);
+ INSERT INTO aux.t1 VALUES(2, NULL);
+ INSERT INTO aux.t1 VALUES(9, NULL);
+ DETACH aux;
+ CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
+ 'VALUES
+ ("test.db1", "t1", 1, 10),
+ ("test.db2", "t1", 11, 20)
+ ', 'fetch_db'
+ );
+} {}
+
+do_catchsql_test 3.3.2 { SELECT * FROM xyz } {1 {fetch_db error!}}
+
+
+
+finish_test
diff --git a/third_party/sqlite/src/test/swarmvtab2.test b/third_party/sqlite/src/test/swarmvtab2.test
new file mode 100644
index 0000000..cf1bdd0
--- /dev/null
+++ b/third_party/sqlite/src/test/swarmvtab2.test
@@ -0,0 +1,75 @@
+# 2017-07-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 file implements regression tests for SQLite library. The
+# focus of this file is the "swarmvtab" extension
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix swarmvtab
+do_not_use_codec
+
+ifcapable !vtab {
+ finish_test
+ return
+}
+
+
+db close
+foreach name [glob -nocomplain test*.db] {
+ forcedelete $name
+}
+sqlite3 db test.db
+load_static_extension db unionvtab
+proc create_database {filename} {
+ sqlite3 dbx $filename
+ set num [regsub -all {[^0-9]+} $filename {}]
+ set num [string trimleft $num 0]
+ set start [expr {$num*1000}]
+ set end [expr {$start+999}]
+ dbx eval {
+ CREATE TABLE t2(a INTEGER PRIMARY KEY,b);
+ WITH RECURSIVE c(x) AS (
+ VALUES($start) UNION ALL SELECT x+1 FROM c WHERE x<$end
+ )
+ INSERT INTO t2(a,b) SELECT x, printf('**%05d**',x) FROM c;
+ }
+ dbx close
+}
+db func create_database create_database
+do_execsql_test 100 {
+ CREATE TABLE t1(filename, tablename, istart, iend);
+ WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<99)
+ INSERT INTO t1 SELECT printf('test%03d.db',x),'t2',x*1000,x*1000+999 FROM c;
+ CREATE VIRTUAL TABLE temp.v1 USING swarmvtab(
+ 'SELECT * FROM t1', 'create_database'
+ );
+} {}
+do_execsql_test 110 {
+ SELECT b FROM v1 WHERE a=3875;
+} {**03875**}
+do_test 120 {
+ lsort [glob -nocomplain test?*.db]
+} {test001.db test003.db}
+do_execsql_test 130 {
+ SELECT b FROM v1 WHERE a BETWEEN 3999 AND 4000 ORDER BY a;
+} {**03999** **04000**}
+do_test 140 {
+ lsort [glob -nocomplain test?*.db]
+} {test001.db test003.db test004.db}
+do_execsql_test 150 {
+ SELECT b FROM v1 WHERE a>=99998;
+} {**99998** **99999**}
+do_test 160 {
+ lsort -dictionary [glob -nocomplain test?*.db]
+} {test001.db test003.db test004.db test099.db}
+
+finish_test
diff --git a/third_party/sqlite/src/test/swarmvtabfault.test b/third_party/sqlite/src/test/swarmvtabfault.test
new file mode 100644
index 0000000..083d80d
--- /dev/null
+++ b/third_party/sqlite/src/test/swarmvtabfault.test
@@ -0,0 +1,66 @@
+# 2017-07-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 file implements regression tests for SQLite library. The
+# focus of this file is error handling in the swarmvtab extension.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix swarmvtabfault
+
+ifcapable !vtab {
+ finish_test
+ return
+}
+
+proc fetch_db {file} {
+ forcedelete $file
+ sqlite3 dbX $file
+ set rc [catch {
+ dbX eval { CREATE TABLE t1(a INTEGER PRIMARY KEY, b) }
+ } res]
+ dbX close
+ if {$rc!=0} {error $res}
+}
+
+forcedelete test.db1
+forcedelete test.db2
+
+do_execsql_test 1.0 {
+ ATTACH 'test.db1' AS aux;
+ CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b);
+ INSERT INTO aux.t1 VALUES(1, NULL);
+ INSERT INTO aux.t1 VALUES(2, NULL);
+ INSERT INTO aux.t1 VALUES(9, NULL);
+ DETACH aux;
+} {}
+
+faultsim_save_and_close
+do_faultsim_test 1.1 -faults oom* -prep {
+ faultsim_restore_and_reopen
+ db func fetch_db fetch_db
+ load_static_extension db unionvtab
+ db eval {
+ CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
+ 'VALUES
+ ("test.db1", "t1", 1, 10),
+ ("test.db2", "t1", 11, 20)
+ ', 'fetch_db'
+ );
+ }
+} -body {
+ execsql { SELECT a FROM xyz }
+} -test {
+ faultsim_test_result {0 {1 2 9}} {1 {sql error: out of memory}}
+}
+
+finish_test
+
diff --git a/third_party/sqlite/src/test/syscall.test b/third_party/sqlite/src/test/syscall.test
index 442f942..045631b 100644
--- a/third_party/sqlite/src/test/syscall.test
+++ b/third_party/sqlite/src/test/syscall.test
@@ -61,7 +61,7 @@ foreach s {
fcntl read pread write pwrite fchmod fallocate
pread64 pwrite64 unlink openDirectory mkdir rmdir
statvfs fchown geteuid umask mmap munmap mremap
- getpagesize readlink lstat
+ getpagesize readlink lstat ioctl
} {
if {[test_syscall exists $s]} {lappend syscall_list $s}
}
diff --git a/third_party/sqlite/src/test/tester.tcl b/third_party/sqlite/src/test/tester.tcl
index 7837ad6..82401fc 100644
--- a/third_party/sqlite/src/test/tester.tcl
+++ b/third_party/sqlite/src/test/tester.tcl
@@ -1241,14 +1241,6 @@ proc show_memstats {} {
set x [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0]
set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]]
output1 "Page-cache overflow: $val"
- set x [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0]
- set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]]
- output1 "Scratch memory used: $val"
- set x [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0]
- set y [sqlite3_status SQLITE_STATUS_SCRATCH_SIZE 0]
- set val [format {now %10d max %10d max-size %10d} \
- [lindex $x 1] [lindex $x 2] [lindex $y 2]]
- output1 "Scratch overflow: $val"
ifcapable yytrackmaxstackdepth {
set x [sqlite3_status SQLITE_STATUS_PARSER_STACK 0]
set val [format { max %10d} [lindex $x 2]]
@@ -1608,6 +1600,54 @@ proc crashsql {args} {
lappend r $msg
}
+# crash_on_write ?-devchar DEVCHAR? CRASHDELAY SQL
+#
+proc crash_on_write {args} {
+
+ set nArg [llength $args]
+ if {$nArg<2 || $nArg%2} {
+ error "bad args: $args"
+ }
+ set zSql [lindex $args end]
+ set nDelay [lindex $args end-1]
+
+ set devchar {}
+ for {set ii 0} {$ii < $nArg-2} {incr ii 2} {
+ set opt [lindex $args $ii]
+ switch -- [lindex $args $ii] {
+ -devchar {
+ set devchar [lindex $args [expr $ii+1]]
+ }
+
+ default { error "unrecognized option: $opt" }
+ }
+ }
+
+ set f [open crash.tcl w]
+ puts $f "sqlite3_crash_on_write $nDelay"
+ puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte"
+ puts $f "sqlite3 db test.db -vfs writecrash"
+ puts $f "db eval {$zSql}"
+ puts $f "set {} {}"
+
+ close $f
+ set r [catch {
+ exec [info nameofexec] crash.tcl >@stdout
+ } msg]
+
+ # Windows/ActiveState TCL returns a slightly different
+ # error message. We map that to the expected message
+ # so that we don't have to change all of the test
+ # cases.
+ if {$::tcl_platform(platform)=="windows"} {
+ if {$msg=="child killed: unknown signal"} {
+ set msg "child process exited abnormally"
+ }
+ }
+
+ lappend r $msg
+}
+
proc run_ioerr_prep {} {
set ::sqlite_io_error_pending 0
catch {db close}
diff --git a/third_party/sqlite/src/test/unionvtabfault.test b/third_party/sqlite/src/test/unionvtabfault.test
index 33cda7b..937d1ec 100644
--- a/third_party/sqlite/src/test/unionvtabfault.test
+++ b/third_party/sqlite/src/test/unionvtabfault.test
@@ -63,6 +63,18 @@ do_faultsim_test 1.2 -faults oom* -prep {
faultsim_test_result {0 {1 one 2 two 3 three 10 ten 11 eleven 12 twelve 20 twenty 21 twenty-one 22 twenty-two}}
}
+#-------------------------------------------------------------------------
+# Error while registering the two vtab modules.
+do_faultsim_test 2.0 -faults * -prep {
+ catch { db close }
+ sqlite3 db :memory:
+} -body {
+ load_static_extension db unionvtab
+} -test {
+ faultsim_test_result {0 {}} {1 {initialization of unionvtab failed: }}
+}
+
+
finish_test
diff --git a/third_party/sqlite/src/test/vtab2.test b/third_party/sqlite/src/test/vtab2.test
index 545a76f..7de8e5b 100644
--- a/third_party/sqlite/src/test/vtab2.test
+++ b/third_party/sqlite/src/test/vtab2.test
@@ -60,7 +60,7 @@ do_test vtab2-2.1 {
set ::abc 123
execsql {
CREATE VIRTUAL TABLE vars USING tclvar;
- SELECT * FROM vars WHERE name='abc';
+ SELECT name, arrayname, value FROM vars WHERE name='abc';
}
} [list abc "" 123]
do_test vtab2-2.2 {
@@ -68,7 +68,7 @@ do_test vtab2-2.2 {
set A(2) 4
set A(3) 9
execsql {
- SELECT * FROM vars WHERE name='A';
+ SELECT name, arrayname, value FROM vars WHERE name='A';
}
} [list A 1 1 A 2 4 A 3 9]
unset -nocomplain result
diff --git a/third_party/sqlite/src/test/vtabE.test b/third_party/sqlite/src/test/vtabE.test
index aeb478e..cbb6a1e 100644
--- a/third_party/sqlite/src/test/vtabE.test
+++ b/third_party/sqlite/src/test/vtabE.test
@@ -39,7 +39,9 @@ do_test vtabE-1 {
CREATE VIRTUAL TABLE t1 USING tclvar;
CREATE VIRTUAL TABLE t2 USING tclvar;
CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
- SELECT t1.*, t2.*, abs(t3.b + abs(t2.value + abs(t1.value)))
+ SELECT t1.name, t1.arrayname, t1.value,
+ t2.name, t2.arrayname, t2.value,
+ abs(t3.b + abs(t2.value + abs(t1.value)))
FROM t1 LEFT JOIN t2 ON t2.name = t1.arrayname
LEFT JOIN t3 ON t3.a=t2.value
WHERE t1.name = 'vtabE'
diff --git a/third_party/sqlite/src/test/vtabH.test b/third_party/sqlite/src/test/vtabH.test
index 9097592..05b3cd0 100644
--- a/third_party/sqlite/src/test/vtabH.test
+++ b/third_party/sqlite/src/test/vtabH.test
@@ -55,7 +55,7 @@ register_tclvar_module db
set ::xyz 10
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE vars USING tclvar;
- SELECT * FROM vars WHERE name = 'xyz';
+ SELECT name, arrayname, value FROM vars WHERE name = 'xyz';
} {xyz {} 10}
set x1 aback
diff --git a/third_party/sqlite/src/test/vtabJ.test b/third_party/sqlite/src/test/vtabJ.test
new file mode 100644
index 0000000..6a8a8a1
--- /dev/null
+++ b/third_party/sqlite/src/test/vtabJ.test
@@ -0,0 +1,126 @@
+# 2017-08-10
+#
+# 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 tests of writing to WITHOUT ROWID virtual tables
+# using the tclvar eponymous virtual table.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix vtabJ
+
+ifcapable !vtab {
+ finish_test
+ return
+}
+
+register_tclvar_module db
+
+unset -nocomplain vtabJ
+do_test 100 {
+ set vtabJ(1) this
+ set vtabJ(two) is
+ set vtabJ(3) {a test}
+ db eval {
+ SELECT fullname, value FROM tclvar WHERE name='vtabJ' ORDER BY fullname;
+ }
+} {vtabJ(1) this vtabJ(3) {a test} vtabJ(two) is}
+
+do_execsql_test 110 {
+ INSERT INTO tclvar(fullname, value)
+ VALUES('vtabJ(4)',4),('vtabJ(five)',555);
+ SELECT fullname, value FROM tclvar WHERE name='vtabJ' ORDER BY fullname;
+} {vtabJ(1) this vtabJ(3) {a test} vtabJ(4) 4 vtabJ(five) 555 vtabJ(two) is}
+do_test 111 {
+ set res {}
+ foreach vname [lsort [array names vtabJ]] {
+ lappend res vtabJ($vname) $vtabJ($vname)
+ }
+ set res
+} {vtabJ(1) this vtabJ(3) {a test} vtabJ(4) 4 vtabJ(five) 555 vtabJ(two) is}
+
+do_test 120 {
+ db eval {
+ INSERT INTO tclvar(fullname, value) VALUES('vtabJ(4)',444);
+ }
+ set vtabJ(4)
+} {444}
+
+do_test 130 {
+ db eval {
+ INSERT INTO tclvar(fullname, value) VALUES('vtabJ(4)',NULL);
+ }
+ info exists vtabJ(4)
+} {0}
+
+do_test 140 {
+ db eval {
+ UPDATE tclvar SET value=55 WHERE fullname='vtabJ(five)';
+ }
+ set vtabJ(five)
+} {55}
+
+do_test 150 {
+ db eval {
+ UPDATE tclvar SET fullname='vtabJ(5)' WHERE fullname='vtabJ(five)';
+ }
+ set vtabJ(5)
+} {55}
+do_test 151 {
+ info exists vtabJ(five)
+} {0}
+do_test 152 {
+ set res {}
+ foreach vname [lsort [array names vtabJ]] {
+ lappend res vtabJ($vname) $vtabJ($vname)
+ }
+ set res
+} {vtabJ(1) this vtabJ(3) {a test} vtabJ(5) 55 vtabJ(two) is}
+
+do_execsql_test 160 {
+ SELECT fullname FROM tclvar WHERE arrayname='two'
+} {vtabJ(two)}
+do_execsql_test 161 {
+ DELETE FROM tclvar WHERE arrayname='two';
+ SELECT fullname, value FROM tclvar WHERE name='vtabJ' ORDER BY fullname;
+} {vtabJ(1) this vtabJ(3) {a test} vtabJ(5) 55}
+do_test 162 {
+ set res {}
+ foreach vname [lsort [array names vtabJ]] {
+ lappend res vtabJ($vname) $vtabJ($vname)
+ }
+ set res
+} {vtabJ(1) this vtabJ(3) {a test} vtabJ(5) 55}
+
+# Try to trick the module into updating the same variable twice for a
+# single UPDATE statement.
+#
+do_execsql_test 171 {
+ INSERT INTO tclvar(fullname, value) VALUES('xx', 'a');
+ SELECT name, value FROM tclvar where name = 'xx';
+} {xx a}
+do_execsql_test 172 {
+ UPDATE tclvar SET value = value || 't'
+ WHERE name = 'xx' OR name = 'x'||'x';
+ SELECT name, value FROM tclvar where name = 'xx';
+} {xx at}
+do_execsql_test 173 {
+ UPDATE tclvar SET value = value || 't'
+ WHERE name = 'xx' OR name BETWEEN 'xx' AND 'xx';
+ SELECT name, value FROM tclvar where name = 'xx';
+} {xx att}
+
+do_execsql_test 181 {
+ DELETE FROM tclvar WHERE name BETWEEN 'xx' AND 'xx' OR name='xx';
+ SELECT name, value FROM tclvar where name = 'xx';
+} {}
+
+
+finish_test
diff --git a/third_party/sqlite/src/test/wal2.test b/third_party/sqlite/src/test/wal2.test
index 3cff676..5733625 100644
--- a/third_party/sqlite/src/test/wal2.test
+++ b/third_party/sqlite/src/test/wal2.test
@@ -1191,7 +1191,7 @@ if {$::tcl_platform(platform) == "unix"} {
#
foreach {tn sql reslist} {
1 { } {10 0 4 0 6 0}
- 2 { PRAGMA checkpoint_fullfsync = 1 } {10 4 4 2 6 2}
+ 2 { PRAGMA checkpoint_fullfsync = 1 } {10 6 4 3 6 3}
3 { PRAGMA checkpoint_fullfsync = 0 } {10 0 4 0 6 0}
} {
ifcapable default_ckptfullfsync {
@@ -1261,8 +1261,8 @@ foreach {tn settings restart_sync commit_sync ckpt_sync} {
6 {0 1 full} {0 2} {0 1} {0 2}
7 {1 0 off} {0 0} {0 0} {0 0}
- 8 {1 0 normal} {1 0} {0 0} {0 2}
- 9 {1 0 full} {2 0} {1 0} {0 2}
+ 8 {1 0 normal} {0 1} {0 0} {0 2}
+ 9 {1 0 full} {1 1} {1 0} {0 2}
10 {1 1 off} {0 0} {0 0} {0 0}
11 {1 1 normal} {0 1} {0 0} {0 2}
diff --git a/third_party/sqlite/src/test/whereA.test b/third_party/sqlite/src/test/whereA.test
index 78826b1..9747e53 100644
--- a/third_party/sqlite/src/test/whereA.test
+++ b/third_party/sqlite/src/test/whereA.test
@@ -158,5 +158,17 @@ do_test whereA-4.6 {
}
} {2 1 1}
+# Ticket https://sqlite.org/src/tktview/cb91bf4290c211 2017-08-01
+# Assertion fault following PRAGMA reverse_unordered_selects=ON.
+#
+do_execsql_test whereA-5.1 {
+ PRAGMA reverse_unordered_selects=on;
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(a,b);
+ INSERT INTO t1 VALUES(1,2);
+ CREATE INDEX t1b ON t1(b);
+ SELECT a FROM t1 WHERE b=-99 OR b>1;
+} {1}
+
finish_test
diff --git a/third_party/sqlite/src/test/whereF.test b/third_party/sqlite/src/test/whereF.test
index bc64945..b0a49f0 100644
--- a/third_party/sqlite/src/test/whereF.test
+++ b/third_party/sqlite/src/test/whereF.test
@@ -176,4 +176,43 @@ do_execsql_test 5.5 {
} {4}
do_test 5.6 { expr [db status vmstep]<200 } 1
+# 2017-09-04 ticket b899b6042f97f52d
+# Segfault on correlated subquery...
+#
+ifcapable json1&&vtab {
+ do_execsql_test 6.1 {
+ CREATE TABLE t6(x);
+ SELECT * FROM t6 WHERE 1 IN (SELECT value FROM json_each(x));
+ } {}
+
+ do_execsql_test 6.2 {
+ DROP TABLE t6;
+ CREATE TABLE t6(a,b,c);
+ INSERT INTO t6 VALUES
+ (0,null,'{"a":0,"b":[3,4,5],"c":{"x":4.5,"y":7.8}}'),
+ (1,null,'{"a":1,"b":[3,4,5],"c":{"x":4.5,"y":7.8}}'),
+ (2,null,'{"a":9,"b":[3,4,5],"c":{"x":4.5,"y":7.8}}');
+ SELECT * FROM t6
+ WHERE (EXISTS (SELECT 1 FROM json_each(t6.c) AS x WHERE x.value=1));
+ } {1 {} {{"a":1,"b":[3,4,5],"c":{"x":4.5,"y":7.8}}}}
+
+ # Another test case derived from a posting by Wout Mertens on the
+ # sqlite-users mailing list on 2017-10-04.
+ do_execsql_test 6.3 {
+ DROP TABLE IF EXISTS t;
+ CREATE TABLE t(json JSON);
+ SELECT * FROM t
+ WHERE(EXISTS(SELECT 1 FROM json_each(t.json,"$.foo") j
+ WHERE j.value = 'meep'));
+ } {}
+ do_execsql_test 6.4 {
+ INSERT INTO t VALUES('{"xyzzy":null}');
+ INSERT INTO t VALUES('{"foo":"meep","other":12345}');
+ INSERT INTO t VALUES('{"foo":"bingo","alt":5.25}');
+ SELECT * FROM t
+ WHERE(EXISTS(SELECT 1 FROM json_each(t.json,"$.foo") j
+ WHERE j.value = 'meep'));
+ } {{{"foo":"meep","other":12345}}}
+}
+
finish_test
diff --git a/third_party/sqlite/src/test/win32heap.test b/third_party/sqlite/src/test/win32heap.test
index b92f804..82a3f6b 100644
--- a/third_party/sqlite/src/test/win32heap.test
+++ b/third_party/sqlite/src/test/win32heap.test
@@ -9,8 +9,7 @@
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
-# focus of this script is recovery from transient manditory locks
-# that sometimes appear on database files due to anti-virus software.
+# focus of this script is the Win32 heap implementation.
#
if {$tcl_platform(platform)!="windows"} return
diff --git a/third_party/sqlite/src/test/wordcount.c b/third_party/sqlite/src/test/wordcount.c
index facfb57..66b4c03 100644
--- a/third_party/sqlite/src/test/wordcount.c
+++ b/third_party/sqlite/src/test/wordcount.c
@@ -633,14 +633,10 @@ int main(int argc, char **argv){
printf("%s Outstanding Allocations: %d (max %d)\n",zTag,iCur,iHiwtr);
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, 0);
printf("%s Pcache Overflow Bytes: %d (max %d)\n",zTag,iCur,iHiwtr);
- sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, 0);
- printf("%s Scratch Overflow Bytes: %d (max %d)\n",zTag,iCur,iHiwtr);
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, 0);
printf("%s Largest Allocation: %d bytes\n",zTag,iHiwtr);
sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, 0);
printf("%s Largest Pcache Allocation: %d bytes\n",zTag,iHiwtr);
- sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, 0);
- printf("%s Largest Scratch Allocation: %d bytes\n",zTag,iHiwtr);
}
return 0;
}
diff --git a/third_party/sqlite/src/test/writecrash.test b/third_party/sqlite/src/test/writecrash.test
new file mode 100644
index 0000000..01bc4db
--- /dev/null
+++ b/third_party/sqlite/src/test/writecrash.test
@@ -0,0 +1,68 @@
+# 2009 January 8
+#
+# 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.
+#
+#***********************************************************************
+#
+# Test the outcome of a writer crashing within a call to the VFS
+# xWrite function.
+#
+
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix writecrash
+
+do_not_use_codec
+
+
+if {$tcl_platform(platform)=="windows"} {
+ finish_test
+ return
+}
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB UNIQUE);
+ WITH s(i) AS (
+ VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100
+ )
+ INSERT INTO t1 SELECT NULL, randomblob(900) FROM s;
+} {}
+
+set bGo 1
+for {set tn 1} {$bGo} {incr tn} {
+
+db close
+sqlite3 db test.db
+
+ do_test 1.$tn.1 {
+ set res [crash_on_write $tn {
+ UPDATE t1 SET b = randomblob(899) WHERE (a%3)==0
+ }]
+ set bGo 0
+ if {[string match {1 {child killed:*}} $res]} {
+ set res {0 {}}
+ set bGo 1
+ }
+ set res
+ } {0 {}}
+
+#db close
+#sqlite3 db test.db
+
+ do_execsql_test 1.$tn.2 { PRAGMA integrity_check } {ok}
+
+db close
+sqlite3 db test.db
+
+ do_execsql_test 1.$tn.3 { PRAGMA integrity_check } {ok}
+}
+
+
+
+finish_test
diff --git a/third_party/sqlite/src/tool/addopcodes.tcl b/third_party/sqlite/src/tool/addopcodes.tcl
index 2c204c6..80ba5c8 100644
--- a/third_party/sqlite/src/tool/addopcodes.tcl
+++ b/third_party/sqlite/src/tool/addopcodes.tcl
@@ -22,14 +22,7 @@ close $in
# ILLEGAL *must* be the last two token codes and they must be in that order.
#
set extras {
- TO_TEXT
- TO_BLOB
- TO_NUMERIC
- TO_INT
- TO_REAL
ISNOT
- END_OF_FILE
- UNCLOSED_STRING
FUNCTION
COLUMN
AGG_FUNCTION
@@ -42,6 +35,8 @@ set extras {
IF_NULL_ROW
ASTERISK
SPAN
+ END_OF_FILE
+ UNCLOSED_STRING
SPACE
ILLEGAL
}
diff --git a/third_party/sqlite/src/tool/lemon.c b/third_party/sqlite/src/tool/lemon.c
index fe0fb4c..acc5450 100644
--- a/third_party/sqlite/src/tool/lemon.c
+++ b/third_party/sqlite/src/tool/lemon.c
@@ -2155,7 +2155,8 @@ enum e_state {
WAITING_FOR_FALLBACK_ID,
WAITING_FOR_WILDCARD_ID,
WAITING_FOR_CLASS_ID,
- WAITING_FOR_CLASS_TOKEN
+ WAITING_FOR_CLASS_TOKEN,
+ WAITING_FOR_TOKEN_NAME
};
struct pstate {
char *filename; /* Name of the input file */
@@ -2470,6 +2471,8 @@ to follow the previous rule.");
}else if( strcmp(x,"fallback")==0 ){
psp->fallback = 0;
psp->state = WAITING_FOR_FALLBACK_ID;
+ }else if( strcmp(x,"token")==0 ){
+ psp->state = WAITING_FOR_TOKEN_NAME;
}else if( strcmp(x,"wildcard")==0 ){
psp->state = WAITING_FOR_WILDCARD_ID;
}else if( strcmp(x,"token_class")==0 ){
@@ -2624,6 +2627,26 @@ to follow the previous rule.");
}
}
break;
+ case WAITING_FOR_TOKEN_NAME:
+ /* Tokens do not have to be declared before use. But they can be
+ ** in order to control their assigned integer number. The number for
+ ** each token is assigned when it is first seen. So by including
+ **
+ ** %token ONE TWO THREE
+ **
+ ** early in the grammar file, that assigns small consecutive values
+ ** to each of the tokens ONE TWO and THREE.
+ */
+ if( x[0]=='.' ){
+ psp->state = WAITING_FOR_DECL_OR_RULE;
+ }else if( !ISUPPER(x[0]) ){
+ ErrorMsg(psp->filename, psp->tokenlineno,
+ "%%token argument \"%s\" should be a token", x);
+ psp->errorcnt++;
+ }else{
+ (void)Symbol_new(x);
+ }
+ break;
case WAITING_FOR_WILDCARD_ID:
if( x[0]=='.' ){
psp->state = WAITING_FOR_DECL_OR_RULE;
diff --git a/third_party/sqlite/src/tool/lempar.c b/third_party/sqlite/src/tool/lempar.c
index 866d9ee..f24684f 100644
--- a/third_party/sqlite/src/tool/lempar.c
+++ b/third_party/sqlite/src/tool/lempar.c
@@ -75,7 +75,8 @@
** YY_MAX_SHIFT Maximum value for shift actions
** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
-** YY_MIN_REDUCE Maximum value for reduce actions
+** YY_MIN_REDUCE Minimum value for reduce actions
+** YY_MAX_REDUCE Maximum value for reduce actions
** YY_ERROR_ACTION The yy_action[] code for syntax error
** YY_ACCEPT_ACTION The yy_action[] code for accept
** YY_NO_ACTION The yy_action[] code for no-op
diff --git a/third_party/sqlite/src/tool/mkautoconfamal.sh b/third_party/sqlite/src/tool/mkautoconfamal.sh
index d7cea68..363c604 100644
--- a/third_party/sqlite/src/tool/mkautoconfamal.sh
+++ b/third_party/sqlite/src/tool/mkautoconfamal.sh
@@ -51,7 +51,7 @@ cp sqlite3.h $TMPSPACE
cp sqlite3ext.h $TMPSPACE
cp $TOP/sqlite3.1 $TMPSPACE
cp $TOP/sqlite3.pc.in $TMPSPACE
-cp $TOP/src/shell.c $TMPSPACE
+cp shell.c $TMPSPACE
cp $TOP/src/sqlite3.rc $TMPSPACE
cp $TOP/tool/Replace.cs $TMPSPACE
diff --git a/third_party/sqlite/src/tool/mkccode.tcl b/third_party/sqlite/src/tool/mkccode.tcl
new file mode 100755
index 0000000..41b09f1
--- /dev/null
+++ b/third_party/sqlite/src/tool/mkccode.tcl
@@ -0,0 +1,93 @@
+#!/usr/bin/tclsh
+#
+# Use this script to build C-language source code for a program that uses
+# tclsqlite.c together with custom TCL scripts and/or C extensions for
+# either SQLite or TCL.
+#
+# Usage example:
+#
+# tclsh mktclsqliteprog.tcl demoapp.c.in >demoapp.c
+#
+# The demoapp.c.in file contains a mixture of C code, TCL script, and
+# processing directives used by mktclsqliteprog.tcl to build the final C-code
+# output file. Most lines of demoapp.c.in are copied straight through into
+# the output. The following control directives are recognized:
+#
+# BEGIN_STRING
+#
+# This marks the beginning of large string literal - usually a TCL
+# script of some kind. Subsequent lines of text through the first
+# line that begins with END_STRING are converted into a C-language
+# string literal.
+#
+# INCLUDE path
+#
+# The path argument is the name of a file to be inserted in place of
+# the INCLUDE line. The path can begin with $ROOT to signify the
+# root of the SQLite source tree, or $HOME to signify the directory
+# that contains the demoapp.c.in input script itself. If the path does
+# not begin with either $ROOT or $HOME, then it is interpreted relative
+# to the current working directory.
+#
+# If the INCLUDE occurs in the middle of BEGIN_STRING...END_STRING
+# then all of the text in the input file is converted into C-language
+# string literals.
+#
+# None of the control directives described above will nest. Only the
+# top-level input file ("demoapp.c.in" in the example) is interpreted.
+# referenced files are copied verbatim.
+#
+if {[llength $argv]!=1} {
+ puts stderr "Usage: $argv0 TEMPLATE >OUTPUT"
+ exit 1
+}
+set infile [lindex $argv 0]
+set ROOT [file normalize [file dir $argv0]/..]
+set HOME [file normalize [file dir $infile]]
+set in [open $infile rb]
+puts [subst {/* DO NOT EDIT
+**
+** This file was generated by \"$argv0 $infile\".
+** To make changes, edit $infile then rerun the generator
+** command.
+*/}]
+set instr 0
+while {1} {
+ set line [gets $in]
+ if {[eof $in]} break
+ if {[regexp {^INCLUDE (.*)} $line all path]} {
+ regsub {^\$ROOT\y} $path $ROOT path
+ regsub {^\$HOME\y} $path $HOME path
+ set in2 [open $path rb]
+ puts "/* INCLUDE $path */"
+ if {$instr} {
+ while {1} {
+ set line [gets $in2]
+ if {[eof $in2]} break
+ set x [string map "\\\\ \\\\\\\\ \\\" \\\\\"" $line]
+ puts "\"$x\\n\""
+ }
+ } else {
+ puts [read $in2]
+ }
+ puts "/* END $path */"
+ close $in2
+ continue
+ }
+ if {[regexp {^BEGIN_STRING} $line]} {
+ set instr 1
+ puts "/* BEGIN_STRING */"
+ continue
+ }
+ if {[regexp {^END_STRING} $line]} {
+ set instr 0
+ puts "/* END_STRING */"
+ continue
+ }
+ if {$instr} {
+ set x [string map "\\\\ \\\\\\\\ \\\" \\\\\"" $line]
+ puts "\"$x\\n\""
+ } else {
+ puts $line
+ }
+}
diff --git a/third_party/sqlite/src/tool/mkopcodeh.tcl b/third_party/sqlite/src/tool/mkopcodeh.tcl
index e15c5fa..969d5d5 100644
--- a/third_party/sqlite/src/tool/mkopcodeh.tcl
+++ b/third_party/sqlite/src/tool/mkopcodeh.tcl
@@ -202,19 +202,17 @@ for {set i 0} {$i<=$max} {incr i} {
set name $def($i)
puts -nonewline [format {#define %-16s %3d} $name $i]
set com {}
+ if {$jump($name)} {
+ lappend com "jump"
+ }
if {[info exists sameas($i)]} {
- set com "same as $sameas($i)"
+ lappend com "same as $sameas($i)"
}
if {[info exists synopsis($name)]} {
- set x $synopsis($name)
- if {$com==""} {
- set com "synopsis: $x"
- } else {
- append com ", synopsis: $x"
- }
+ lappend com "synopsis: $synopsis($name)"
}
- if {$com!=""} {
- puts -nonewline [format " /* %-42s */" $com]
+ if {[llength $com]} {
+ puts -nonewline [format " /* %-42s */" [join $com {, }]]
}
puts ""
}
diff --git a/third_party/sqlite/src/tool/mkshellc.tcl b/third_party/sqlite/src/tool/mkshellc.tcl
index 66f09e8..6974ade 100644
--- a/third_party/sqlite/src/tool/mkshellc.tcl
+++ b/third_party/sqlite/src/tool/mkshellc.tcl
@@ -1,11 +1,16 @@
#!/usr/bin/tclsh
#
-# Run this script to generate the "src/shell.c" source file from
+# Run this script to generate the "shell.c" source file from
# constituent parts.
#
+# No arguments are required. This script determines the location
+# of its input files relative to the location of the script itself.
+# This script should be tool/mkshellc.tcl. If the directory holding
+# the script is $DIR, then the component parts are located in $DIR/../src
+# and $DIR/../ext/misc.
+#
set topdir [file dir [file dir [file normal $argv0]]]
-puts "Overwriting $topdir/src/shell.c with new shell source code..."
-set out [open $topdir/src/shell.c wb]
+set out stdout
puts $out {/* DO NOT EDIT!
** This file is automatically generated by the script in the canonical
** SQLite source tree at tool/mkshellc.tcl. That script combines source
@@ -25,8 +30,9 @@ puts $out {/* DO NOT EDIT!
** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script.
*/}
set in [open $topdir/src/shell.c.in rb]
-while {![eof $in]} {
+while {1} {
set lx [gets $in]
+ if {[eof $in]} break;
if {[regexp {^INCLUDE } $lx]} {
set cfile [lindex $lx 1]
puts $out "/************************* Begin $cfile ******************/"
@@ -34,6 +40,7 @@ while {![eof $in]} {
while {![eof $in2]} {
set lx [gets $in2]
if {[regexp {^#include "sqlite} $lx]} continue
+ set lx [string map [list __declspec(dllexport) {}] $lx]
puts $out $lx
}
close $in2
diff --git a/third_party/sqlite/src/tool/mksourceid.c b/third_party/sqlite/src/tool/mksourceid.c
new file mode 100644
index 0000000..3f4c213
--- /dev/null
+++ b/third_party/sqlite/src/tool/mksourceid.c
@@ -0,0 +1,853 @@
+/*
+** Run this program with a single argument which is the name of the
+** Fossil "manifest" file for a project, and this program will emit on
+** standard output the "source id" for for the program.
+**
+** (1) The "source id" is the date of check-in together with the
+** SHA3 hash of the manifest file.
+**
+** (2) All individual file hashes in the manifest are verified. If any
+** source file has changed, the SHA3 hash ends with "modified".
+**
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+/* Portable 64-bit unsigned integers */
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+ typedef unsigned __int64 u64;
+#else
+ typedef unsigned long long int u64;
+#endif
+
+
+/*
+** Macros to determine whether the machine is big or little endian,
+** and whether or not that determination is run-time or compile-time.
+**
+** For best performance, an attempt is made to guess at the byte-order
+** using C-preprocessor macros. If that is unsuccessful, or if
+** -DBYTEORDER=0 is set, then byte-order is determined
+** at run-time.
+*/
+#ifndef BYTEORDER
+# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
+ defined(__arm__)
+# define BYTEORDER 1234
+# elif defined(sparc) || defined(__ppc__)
+# define BYTEORDER 4321
+# else
+# define BYTEORDER 0
+# endif
+#endif
+
+
+
+/*
+** State structure for a SHA3 hash in progress
+*/
+typedef struct SHA3Context SHA3Context;
+struct SHA3Context {
+ union {
+ u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */
+ unsigned char x[1600]; /* ... or 1600 bytes */
+ } u;
+ unsigned nRate; /* Bytes of input accepted per Keccak iteration */
+ unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */
+ unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
+};
+
+/*
+** A single step of the Keccak mixing function for a 1600-bit state
+*/
+static void KeccakF1600Step(SHA3Context *p){
+ int i;
+ u64 B0, B1, B2, B3, B4;
+ u64 C0, C1, C2, C3, C4;
+ u64 D0, D1, D2, D3, D4;
+ static const u64 RC[] = {
+ 0x0000000000000001ULL, 0x0000000000008082ULL,
+ 0x800000000000808aULL, 0x8000000080008000ULL,
+ 0x000000000000808bULL, 0x0000000080000001ULL,
+ 0x8000000080008081ULL, 0x8000000000008009ULL,
+ 0x000000000000008aULL, 0x0000000000000088ULL,
+ 0x0000000080008009ULL, 0x000000008000000aULL,
+ 0x000000008000808bULL, 0x800000000000008bULL,
+ 0x8000000000008089ULL, 0x8000000000008003ULL,
+ 0x8000000000008002ULL, 0x8000000000000080ULL,
+ 0x000000000000800aULL, 0x800000008000000aULL,
+ 0x8000000080008081ULL, 0x8000000000008080ULL,
+ 0x0000000080000001ULL, 0x8000000080008008ULL
+ };
+# define A00 (p->u.s[0])
+# define A01 (p->u.s[1])
+# define A02 (p->u.s[2])
+# define A03 (p->u.s[3])
+# define A04 (p->u.s[4])
+# define A10 (p->u.s[5])
+# define A11 (p->u.s[6])
+# define A12 (p->u.s[7])
+# define A13 (p->u.s[8])
+# define A14 (p->u.s[9])
+# define A20 (p->u.s[10])
+# define A21 (p->u.s[11])
+# define A22 (p->u.s[12])
+# define A23 (p->u.s[13])
+# define A24 (p->u.s[14])
+# define A30 (p->u.s[15])
+# define A31 (p->u.s[16])
+# define A32 (p->u.s[17])
+# define A33 (p->u.s[18])
+# define A34 (p->u.s[19])
+# define A40 (p->u.s[20])
+# define A41 (p->u.s[21])
+# define A42 (p->u.s[22])
+# define A43 (p->u.s[23])
+# define A44 (p->u.s[24])
+# define ROL64(a,x) ((a<<x)|(a>>(64-x)))
+
+ for(i=0; i<24; i+=4){
+ C0 = A00^A10^A20^A30^A40;
+ C1 = A01^A11^A21^A31^A41;
+ C2 = A02^A12^A22^A32^A42;
+ C3 = A03^A13^A23^A33^A43;
+ C4 = A04^A14^A24^A34^A44;
+ D0 = C4^ROL64(C1, 1);
+ D1 = C0^ROL64(C2, 1);
+ D2 = C1^ROL64(C3, 1);
+ D3 = C2^ROL64(C4, 1);
+ D4 = C3^ROL64(C0, 1);
+
+ B0 = (A00^D0);
+ B1 = ROL64((A11^D1), 44);
+ B2 = ROL64((A22^D2), 43);
+ B3 = ROL64((A33^D3), 21);
+ B4 = ROL64((A44^D4), 14);
+ A00 = B0 ^((~B1)& B2 );
+ A00 ^= RC[i];
+ A11 = B1 ^((~B2)& B3 );
+ A22 = B2 ^((~B3)& B4 );
+ A33 = B3 ^((~B4)& B0 );
+ A44 = B4 ^((~B0)& B1 );
+
+ B2 = ROL64((A20^D0), 3);
+ B3 = ROL64((A31^D1), 45);
+ B4 = ROL64((A42^D2), 61);
+ B0 = ROL64((A03^D3), 28);
+ B1 = ROL64((A14^D4), 20);
+ A20 = B0 ^((~B1)& B2 );
+ A31 = B1 ^((~B2)& B3 );
+ A42 = B2 ^((~B3)& B4 );
+ A03 = B3 ^((~B4)& B0 );
+ A14 = B4 ^((~B0)& B1 );
+
+ B4 = ROL64((A40^D0), 18);
+ B0 = ROL64((A01^D1), 1);
+ B1 = ROL64((A12^D2), 6);
+ B2 = ROL64((A23^D3), 25);
+ B3 = ROL64((A34^D4), 8);
+ A40 = B0 ^((~B1)& B2 );
+ A01 = B1 ^((~B2)& B3 );
+ A12 = B2 ^((~B3)& B4 );
+ A23 = B3 ^((~B4)& B0 );
+ A34 = B4 ^((~B0)& B1 );
+
+ B1 = ROL64((A10^D0), 36);
+ B2 = ROL64((A21^D1), 10);
+ B3 = ROL64((A32^D2), 15);
+ B4 = ROL64((A43^D3), 56);
+ B0 = ROL64((A04^D4), 27);
+ A10 = B0 ^((~B1)& B2 );
+ A21 = B1 ^((~B2)& B3 );
+ A32 = B2 ^((~B3)& B4 );
+ A43 = B3 ^((~B4)& B0 );
+ A04 = B4 ^((~B0)& B1 );
+
+ B3 = ROL64((A30^D0), 41);
+ B4 = ROL64((A41^D1), 2);
+ B0 = ROL64((A02^D2), 62);
+ B1 = ROL64((A13^D3), 55);
+ B2 = ROL64((A24^D4), 39);
+ A30 = B0 ^((~B1)& B2 );
+ A41 = B1 ^((~B2)& B3 );
+ A02 = B2 ^((~B3)& B4 );
+ A13 = B3 ^((~B4)& B0 );
+ A24 = B4 ^((~B0)& B1 );
+
+ C0 = A00^A20^A40^A10^A30;
+ C1 = A11^A31^A01^A21^A41;
+ C2 = A22^A42^A12^A32^A02;
+ C3 = A33^A03^A23^A43^A13;
+ C4 = A44^A14^A34^A04^A24;
+ D0 = C4^ROL64(C1, 1);
+ D1 = C0^ROL64(C2, 1);
+ D2 = C1^ROL64(C3, 1);
+ D3 = C2^ROL64(C4, 1);
+ D4 = C3^ROL64(C0, 1);
+
+ B0 = (A00^D0);
+ B1 = ROL64((A31^D1), 44);
+ B2 = ROL64((A12^D2), 43);
+ B3 = ROL64((A43^D3), 21);
+ B4 = ROL64((A24^D4), 14);
+ A00 = B0 ^((~B1)& B2 );
+ A00 ^= RC[i+1];
+ A31 = B1 ^((~B2)& B3 );
+ A12 = B2 ^((~B3)& B4 );
+ A43 = B3 ^((~B4)& B0 );
+ A24 = B4 ^((~B0)& B1 );
+
+ B2 = ROL64((A40^D0), 3);
+ B3 = ROL64((A21^D1), 45);
+ B4 = ROL64((A02^D2), 61);
+ B0 = ROL64((A33^D3), 28);
+ B1 = ROL64((A14^D4), 20);
+ A40 = B0 ^((~B1)& B2 );
+ A21 = B1 ^((~B2)& B3 );
+ A02 = B2 ^((~B3)& B4 );
+ A33 = B3 ^((~B4)& B0 );
+ A14 = B4 ^((~B0)& B1 );
+
+ B4 = ROL64((A30^D0), 18);
+ B0 = ROL64((A11^D1), 1);
+ B1 = ROL64((A42^D2), 6);
+ B2 = ROL64((A23^D3), 25);
+ B3 = ROL64((A04^D4), 8);
+ A30 = B0 ^((~B1)& B2 );
+ A11 = B1 ^((~B2)& B3 );
+ A42 = B2 ^((~B3)& B4 );
+ A23 = B3 ^((~B4)& B0 );
+ A04 = B4 ^((~B0)& B1 );
+
+ B1 = ROL64((A20^D0), 36);
+ B2 = ROL64((A01^D1), 10);
+ B3 = ROL64((A32^D2), 15);
+ B4 = ROL64((A13^D3), 56);
+ B0 = ROL64((A44^D4), 27);
+ A20 = B0 ^((~B1)& B2 );
+ A01 = B1 ^((~B2)& B3 );
+ A32 = B2 ^((~B3)& B4 );
+ A13 = B3 ^((~B4)& B0 );
+ A44 = B4 ^((~B0)& B1 );
+
+ B3 = ROL64((A10^D0), 41);
+ B4 = ROL64((A41^D1), 2);
+ B0 = ROL64((A22^D2), 62);
+ B1 = ROL64((A03^D3), 55);
+ B2 = ROL64((A34^D4), 39);
+ A10 = B0 ^((~B1)& B2 );
+ A41 = B1 ^((~B2)& B3 );
+ A22 = B2 ^((~B3)& B4 );
+ A03 = B3 ^((~B4)& B0 );
+ A34 = B4 ^((~B0)& B1 );
+
+ C0 = A00^A40^A30^A20^A10;
+ C1 = A31^A21^A11^A01^A41;
+ C2 = A12^A02^A42^A32^A22;
+ C3 = A43^A33^A23^A13^A03;
+ C4 = A24^A14^A04^A44^A34;
+ D0 = C4^ROL64(C1, 1);
+ D1 = C0^ROL64(C2, 1);
+ D2 = C1^ROL64(C3, 1);
+ D3 = C2^ROL64(C4, 1);
+ D4 = C3^ROL64(C0, 1);
+
+ B0 = (A00^D0);
+ B1 = ROL64((A21^D1), 44);
+ B2 = ROL64((A42^D2), 43);
+ B3 = ROL64((A13^D3), 21);
+ B4 = ROL64((A34^D4), 14);
+ A00 = B0 ^((~B1)& B2 );
+ A00 ^= RC[i+2];
+ A21 = B1 ^((~B2)& B3 );
+ A42 = B2 ^((~B3)& B4 );
+ A13 = B3 ^((~B4)& B0 );
+ A34 = B4 ^((~B0)& B1 );
+
+ B2 = ROL64((A30^D0), 3);
+ B3 = ROL64((A01^D1), 45);
+ B4 = ROL64((A22^D2), 61);
+ B0 = ROL64((A43^D3), 28);
+ B1 = ROL64((A14^D4), 20);
+ A30 = B0 ^((~B1)& B2 );
+ A01 = B1 ^((~B2)& B3 );
+ A22 = B2 ^((~B3)& B4 );
+ A43 = B3 ^((~B4)& B0 );
+ A14 = B4 ^((~B0)& B1 );
+
+ B4 = ROL64((A10^D0), 18);
+ B0 = ROL64((A31^D1), 1);
+ B1 = ROL64((A02^D2), 6);
+ B2 = ROL64((A23^D3), 25);
+ B3 = ROL64((A44^D4), 8);
+ A10 = B0 ^((~B1)& B2 );
+ A31 = B1 ^((~B2)& B3 );
+ A02 = B2 ^((~B3)& B4 );
+ A23 = B3 ^((~B4)& B0 );
+ A44 = B4 ^((~B0)& B1 );
+
+ B1 = ROL64((A40^D0), 36);
+ B2 = ROL64((A11^D1), 10);
+ B3 = ROL64((A32^D2), 15);
+ B4 = ROL64((A03^D3), 56);
+ B0 = ROL64((A24^D4), 27);
+ A40 = B0 ^((~B1)& B2 );
+ A11 = B1 ^((~B2)& B3 );
+ A32 = B2 ^((~B3)& B4 );
+ A03 = B3 ^((~B4)& B0 );
+ A24 = B4 ^((~B0)& B1 );
+
+ B3 = ROL64((A20^D0), 41);
+ B4 = ROL64((A41^D1), 2);
+ B0 = ROL64((A12^D2), 62);
+ B1 = ROL64((A33^D3), 55);
+ B2 = ROL64((A04^D4), 39);
+ A20 = B0 ^((~B1)& B2 );
+ A41 = B1 ^((~B2)& B3 );
+ A12 = B2 ^((~B3)& B4 );
+ A33 = B3 ^((~B4)& B0 );
+ A04 = B4 ^((~B0)& B1 );
+
+ C0 = A00^A30^A10^A40^A20;
+ C1 = A21^A01^A31^A11^A41;
+ C2 = A42^A22^A02^A32^A12;
+ C3 = A13^A43^A23^A03^A33;
+ C4 = A34^A14^A44^A24^A04;
+ D0 = C4^ROL64(C1, 1);
+ D1 = C0^ROL64(C2, 1);
+ D2 = C1^ROL64(C3, 1);
+ D3 = C2^ROL64(C4, 1);
+ D4 = C3^ROL64(C0, 1);
+
+ B0 = (A00^D0);
+ B1 = ROL64((A01^D1), 44);
+ B2 = ROL64((A02^D2), 43);
+ B3 = ROL64((A03^D3), 21);
+ B4 = ROL64((A04^D4), 14);
+ A00 = B0 ^((~B1)& B2 );
+ A00 ^= RC[i+3];
+ A01 = B1 ^((~B2)& B3 );
+ A02 = B2 ^((~B3)& B4 );
+ A03 = B3 ^((~B4)& B0 );
+ A04 = B4 ^((~B0)& B1 );
+
+ B2 = ROL64((A10^D0), 3);
+ B3 = ROL64((A11^D1), 45);
+ B4 = ROL64((A12^D2), 61);
+ B0 = ROL64((A13^D3), 28);
+ B1 = ROL64((A14^D4), 20);
+ A10 = B0 ^((~B1)& B2 );
+ A11 = B1 ^((~B2)& B3 );
+ A12 = B2 ^((~B3)& B4 );
+ A13 = B3 ^((~B4)& B0 );
+ A14 = B4 ^((~B0)& B1 );
+
+ B4 = ROL64((A20^D0), 18);
+ B0 = ROL64((A21^D1), 1);
+ B1 = ROL64((A22^D2), 6);
+ B2 = ROL64((A23^D3), 25);
+ B3 = ROL64((A24^D4), 8);
+ A20 = B0 ^((~B1)& B2 );
+ A21 = B1 ^((~B2)& B3 );
+ A22 = B2 ^((~B3)& B4 );
+ A23 = B3 ^((~B4)& B0 );
+ A24 = B4 ^((~B0)& B1 );
+
+ B1 = ROL64((A30^D0), 36);
+ B2 = ROL64((A31^D1), 10);
+ B3 = ROL64((A32^D2), 15);
+ B4 = ROL64((A33^D3), 56);
+ B0 = ROL64((A34^D4), 27);
+ A30 = B0 ^((~B1)& B2 );
+ A31 = B1 ^((~B2)& B3 );
+ A32 = B2 ^((~B3)& B4 );
+ A33 = B3 ^((~B4)& B0 );
+ A34 = B4 ^((~B0)& B1 );
+
+ B3 = ROL64((A40^D0), 41);
+ B4 = ROL64((A41^D1), 2);
+ B0 = ROL64((A42^D2), 62);
+ B1 = ROL64((A43^D3), 55);
+ B2 = ROL64((A44^D4), 39);
+ A40 = B0 ^((~B1)& B2 );
+ A41 = B1 ^((~B2)& B3 );
+ A42 = B2 ^((~B3)& B4 );
+ A43 = B3 ^((~B4)& B0 );
+ A44 = B4 ^((~B0)& B1 );
+ }
+}
+
+/*
+** Initialize a new hash. iSize determines the size of the hash
+** in bits and should be one of 224, 256, 384, or 512. Or iSize
+** can be zero to use the default hash size of 256 bits.
+*/
+static void SHA3Init(SHA3Context *p, int iSize){
+ memset(p, 0, sizeof(*p));
+ if( iSize>=128 && iSize<=512 ){
+ p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
+ }else{
+ p->nRate = (1600 - 2*256)/8;
+ }
+#if BYTEORDER==1234
+ /* Known to be little-endian at compile-time. No-op */
+#elif BYTEORDER==4321
+ p->ixMask = 7; /* Big-endian */
+#else
+ {
+ static unsigned int one = 1;
+ if( 1==*(unsigned char*)&one ){
+ /* Little endian. No byte swapping. */
+ p->ixMask = 0;
+ }else{
+ /* Big endian. Byte swap. */
+ p->ixMask = 7;
+ }
+ }
+#endif
+}
+
+/*
+** Make consecutive calls to the SHA3Update function to add new content
+** to the hash
+*/
+static void SHA3Update(
+ SHA3Context *p,
+ const unsigned char *aData,
+ unsigned int nData
+){
+ unsigned int i = 0;
+#if BYTEORDER==1234
+ if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
+ for(; i+7<nData; i+=8){
+ p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
+ p->nLoaded += 8;
+ if( p->nLoaded>=p->nRate ){
+ KeccakF1600Step(p);
+ p->nLoaded = 0;
+ }
+ }
+ }
+#endif
+ for(; i<nData; i++){
+#if BYTEORDER==1234
+ p->u.x[p->nLoaded] ^= aData[i];
+#elif BYTEORDER==4321
+ p->u.x[p->nLoaded^0x07] ^= aData[i];
+#else
+ p->u.x[p->nLoaded^p->ixMask] ^= aData[i];
+#endif
+ p->nLoaded++;
+ if( p->nLoaded==p->nRate ){
+ KeccakF1600Step(p);
+ p->nLoaded = 0;
+ }
+ }
+}
+
+/*
+** After all content has been added, invoke SHA3Final() to compute
+** the final hash. The function returns a pointer to the binary
+** hash value.
+*/
+static unsigned char *SHA3Final(SHA3Context *p){
+ unsigned int i;
+ if( p->nLoaded==p->nRate-1 ){
+ const unsigned char c1 = 0x86;
+ SHA3Update(p, &c1, 1);
+ }else{
+ const unsigned char c2 = 0x06;
+ const unsigned char c3 = 0x80;
+ SHA3Update(p, &c2, 1);
+ p->nLoaded = p->nRate - 1;
+ SHA3Update(p, &c3, 1);
+ }
+ for(i=0; i<p->nRate; i++){
+ p->u.x[i+p->nRate] = p->u.x[i^p->ixMask];
+ }
+ return &p->u.x[p->nRate];
+}
+
+/*
+** Convert a digest into base-16. digest should be declared as
+** "unsigned char digest[20]" in the calling function. The SHA3
+** digest is stored in the first 20 bytes. zBuf should
+** be "char zBuf[41]".
+*/
+static void DigestToBase16(unsigned char *digest, char *zBuf, int nByte){
+ static const char zEncode[] = "0123456789abcdef";
+ int ix;
+
+ for(ix=0; ix<nByte; ix++){
+ *zBuf++ = zEncode[(*digest>>4)&0xf];
+ *zBuf++ = zEncode[*digest++ & 0xf];
+ }
+ *zBuf = '\0';
+}
+
+
+/*
+** Compute the SHA3 checksum of a file on disk. Store the resulting
+** checksum in the blob pCksum. pCksum is assumed to be initialized.
+**
+** Return the number of errors.
+*/
+static int sha3sum_file(const char *zFilename, int iSize, char *pCksum){
+ FILE *in;
+ SHA3Context ctx;
+ char zBuf[10240];
+
+ in = fopen(zFilename,"rb");
+ if( in==0 ){
+ return 1;
+ }
+ SHA3Init(&ctx, iSize);
+ for(;;){
+ int n = (int)fread(zBuf, 1, sizeof(zBuf), in);
+ if( n<=0 ) break;
+ SHA3Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
+ }
+ fclose(in);
+ DigestToBase16(SHA3Final(&ctx), pCksum, iSize/8);
+ return 0;
+}
+
+/*
+** The SHA1 implementation below is adapted from:
+**
+** $NetBSD: sha1.c,v 1.6 2009/11/06 20:31:18 joerg Exp $
+** $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $
+**
+** SHA-1 in C
+** By Steve Reid <steve@edmweb.com>
+** 100% Public Domain
+*/
+typedef struct SHA1Context SHA1Context;
+struct SHA1Context {
+ unsigned int state[5];
+ unsigned int count[2];
+ unsigned char buffer[64];
+};
+
+/*
+ * blk0() and blk() perform the initial expand.
+ * I got the idea of expanding during the round function from SSLeay
+ *
+ * blk0le() for little-endian and blk0be() for big-endian.
+ */
+#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
+/*
+ * GCC by itself only generates left rotates. Use right rotates if
+ * possible to be kinder to dinky implementations with iterative rotate
+ * instructions.
+ */
+#define SHA_ROT(op, x, k) \
+ ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
+#define rol(x,k) SHA_ROT("roll", x, k)
+#define ror(x,k) SHA_ROT("rorl", x, k)
+
+#else
+/* Generic C equivalent */
+#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
+#define rol(x,k) SHA_ROT(x,k,32-(k))
+#define ror(x,k) SHA_ROT(x,32-(k),k)
+#endif
+
+
+
+
+
+#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
+ |(rol(block[i],8)&0x00FF00FF))
+#define blk0be(i) block[i]
+#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
+ ^block[(i+2)&15]^block[i&15],1))
+
+/*
+ * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
+ *
+ * Rl0() for little-endian and Rb0() for big-endian. Endianness is
+ * determined at run-time.
+ */
+#define Rl0(v,w,x,y,z,i) \
+ z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
+#define Rb0(v,w,x,y,z,i) \
+ z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
+#define R1(v,w,x,y,z,i) \
+ z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2);
+#define R2(v,w,x,y,z,i) \
+ z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2);
+#define R3(v,w,x,y,z,i) \
+ z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2);
+#define R4(v,w,x,y,z,i) \
+ z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
+
+/*
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ */
+#define a qq[0]
+#define b qq[1]
+#define c qq[2]
+#define d qq[3]
+#define e qq[4]
+
+static void SHA1Transform(
+ unsigned int state[5],
+ const unsigned char buffer[64]
+){
+ unsigned int qq[5]; /* a, b, c, d, e; */
+ static int one = 1;
+ unsigned int block[16];
+ memcpy(block, buffer, 64);
+ memcpy(qq,state,5*sizeof(unsigned int));
+
+ /* Copy context->state[] to working vars */
+ /*
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ */
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ if( 1 == *(unsigned char*)&one ){
+ Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3);
+ Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7);
+ Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11);
+ Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15);
+ }else{
+ Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3);
+ Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7);
+ Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11);
+ Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15);
+ }
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+}
+
+
+/*
+ * SHA1Init - Initialize new context
+ */
+static void SHA1Init(SHA1Context *context){
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/*
+ * Run your data through this.
+ */
+static void SHA1Update(
+ SHA1Context *context,
+ const unsigned char *data,
+ unsigned int len
+){
+ unsigned int i, j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1] += (len>>29)+1;
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ (void)memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64)
+ SHA1Transform(context->state, &data[i]);
+ j = 0;
+ } else {
+ i = 0;
+ }
+ (void)memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/*
+ * Add padding and return the message digest.
+ */
+static void SHA1Final(unsigned char *digest, SHA1Context *context){
+ unsigned int i;
+ unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (const unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448)
+ SHA1Update(context, (const unsigned char *)"\0", 1);
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+
+ if (digest) {
+ for (i = 0; i < 20; i++)
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+}
+
+
+/*
+** Compute the SHA1 checksum of a file on disk. Store the resulting
+** checksum in the blob pCksum. pCksum is assumed to be initialized.
+**
+** Return the number of errors.
+*/
+static int sha1sum_file(const char *zFilename, char *pCksum){
+ FILE *in;
+ SHA1Context ctx;
+ unsigned char zResult[20];
+ char zBuf[10240];
+
+ in = fopen(zFilename,"rb");
+ if( in==0 ){
+ return 1;
+ }
+ SHA1Init(&ctx);
+ for(;;){
+ int n = (int)fread(zBuf, 1, sizeof(zBuf), in);
+ if( n<=0 ) break;
+ SHA1Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
+ }
+ fclose(in);
+ SHA1Final(zResult, &ctx);
+ DigestToBase16(zResult, pCksum, 20);
+ return 0;
+}
+
+/*
+** Print a usage comment and quit.
+*/
+static void usage(const char *argv0){
+ fprintf(stderr,
+ "Usage: %s manifest\n"
+ "Options:\n"
+ " -v Diagnostic output\n"
+ , argv0);
+ exit(1);
+}
+
+/*
+** Find the first whitespace character in a string. Set that whitespace
+** to a \000 terminator and return a pointer to the next character.
+*/
+static char *nextToken(char *z){
+ while( *z && !isspace(*z) ) z++;
+ if( *z==0 ) return z;
+ *z = 0;
+ return &z[1];
+}
+
+
+int main(int argc, char **argv){
+ const char *zManifest = 0;
+ int i;
+ int bVerbose = 0;
+ FILE *in;
+ int allValid = 1;
+ int rc;
+ SHA3Context ctx;
+ char zDate[50];
+ char zHash[100];
+ char zLine[20000];
+
+ for(i=1; i<argc; i++){
+ const char *z = argv[i];
+ if( z[0]=='-' ){
+ if( z[1]=='-' ) z++;
+ if( strcmp(z, "-v")==0 ){
+ bVerbose = 1;
+ }else
+ {
+ fprintf(stderr, "unknown option \"%s\"", argv[i]);
+ exit(1);
+ }
+ }else if( zManifest!=0 ){
+ usage(argv[0]);
+ }else{
+ zManifest = z;
+ }
+ }
+ if( zManifest==0 ) usage(argv[0]);
+ zDate[0] = 0;
+ in = fopen(zManifest, "rb");
+ if( in==0 ){
+ fprintf(stderr, "cannot open \"%s\" for reading\n", zManifest);
+ exit(1);
+ }
+ SHA3Init(&ctx, 256);
+ while( fgets(zLine, sizeof(zLine), in) ){
+ if( strncmp(zLine,"# Remove this line", 18)!=0 ){
+ SHA3Update(&ctx, (unsigned char*)zLine, (unsigned)strlen(zLine));
+ }
+ if( strncmp(zLine, "D 20", 4)==0 ){
+ memcpy(zDate, &zLine[2], 10);
+ zDate[10] = ' ';
+ memcpy(&zDate[11], &zLine[13], 8);
+ zDate[19] = 0;
+ continue;
+ }
+ if( strncmp(zLine, "F ", 2)==0 ){
+ char *zFilename = &zLine[2];
+ char *zMHash = nextToken(zFilename);
+ nextToken(zMHash);
+ if( strlen(zMHash)==40 ){
+ rc = sha1sum_file(zFilename, zHash);
+ }else{
+ rc = sha3sum_file(zFilename, 256, zHash);
+ }
+ if( rc ){
+ allValid = 0;
+ if( bVerbose ){
+ printf("hash failed: %s\n", zFilename);
+ }
+ }else if( strcmp(zHash, zMHash)!=0 ){
+ allValid = 0;
+ if( bVerbose ){
+ printf("wrong hash: %s\n", zFilename);
+ printf("... expected: %s\n", zMHash);
+ printf("... got: %s\n", zHash);
+ }
+ }
+ }
+ }
+ fclose(in);
+ DigestToBase16(SHA3Final(&ctx), zHash, 256/8);
+ if( !allValid ){
+ printf("%s %.60salt1\n", zDate, zHash);
+ }else{
+ printf("%s %s\n", zDate, zHash);
+ }
+ return 0;
+}
diff --git a/third_party/sqlite/src/tool/mksqlite3c.tcl b/third_party/sqlite/src/tool/mksqlite3c.tcl
index 596787d4..8ea3e81 100644
--- a/third_party/sqlite/src/tool/mksqlite3c.tcl
+++ b/third_party/sqlite/src/tool/mksqlite3c.tcl
@@ -224,6 +224,8 @@ proc copy_file {filename} {
if {![info exists varonly_hdr($tail)]
&& [regexp $declpattern $line all rettype funcname rest]} {
regsub {^SQLITE_API } $line {} line
+ regsub {^SQLITE_API } $rettype {} rettype
+
# Add the SQLITE_PRIVATE or SQLITE_API keyword before functions.
# so that linkage can be modified at compile-time.
if {[regexp {^sqlite3[a-z]*_} $funcname]} {
@@ -240,7 +242,13 @@ proc copy_file {filename} {
}
}
append line $funcname $rest
- puts $out $line
+ if {$funcname=="sqlite3_sourceid" && !$linemacros} {
+ # The sqlite3_sourceid() routine is synthesized at the end of
+ # the amalgamation
+ puts $out "/* $line */"
+ } else {
+ puts $out $line
+ }
} else {
puts $out "SQLITE_PRIVATE $line"
}
@@ -386,6 +394,7 @@ foreach file {
fts3_icu.c
sqlite3rbu.c
dbstat.c
+ dbpage.c
sqlite3session.c
json1.c
fts5.c
@@ -394,4 +403,34 @@ foreach file {
copy_file tsrc/$file
}
+# Synthesize an alternative sqlite3_sourceid() implementation that
+# that tries to detects changes in the amalgamation source text
+# and modify returns a modified source-id if changes are detected.
+#
+# The only detection mechanism we have is the __LINE__ macro. So only
+# edits that changes the number of lines of source code are detected.
+#
+if {!$linemacros} {
+ flush $out
+ set in2 [open sqlite3.c]
+ set cnt 0
+ set oldsrcid {}
+ while {![eof $in2]} {
+ incr cnt
+ gets $in2 line
+ if {[regexp {^#define SQLITE_SOURCE_ID } $line]} {set oldsrcid $line}
+ }
+ close $in2
+ regsub {[0-9a-flt]{4}"} $oldsrcid {alt2"} oldsrcid
+ puts $out \
+"#if __LINE__!=[expr {$cnt+0}]
+#undef SQLITE_SOURCE_ID
+$oldsrcid
+#endif
+/* Return the source-id for this library */
+SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }"
+}
+puts $out \
+"/************************** End of sqlite3.c ******************************/"
+
close $out
diff --git a/third_party/sqlite/src/tool/mksqlite3h.tcl b/third_party/sqlite/src/tool/mksqlite3h.tcl
index 5106a83..5b4c48b 100644
--- a/third_party/sqlite/src/tool/mksqlite3h.tcl
+++ b/third_party/sqlite/src/tool/mksqlite3h.tcl
@@ -51,24 +51,12 @@ set zVersion [string trim [read $in]]
close $in
set nVersion [eval format "%d%03d%03d" [split $zVersion .]]
-# Get the fossil-scm version number from $TOP/manifest.uuid.
+# Get the source-id
#
-set in [open $TOP/manifest.uuid]
-set zUuid [string trim [read $in]]
-close $in
-
-# Get the fossil-scm check-in date from the "D" card of $TOP/manifest.
-#
-set in [open $TOP/manifest]
-set zDate {}
-while {![eof $in]} {
- set line [gets $in]
- if {[regexp {^D (2[-0-9T:]+)} $line all date]} {
- set zDate [string map {T { }} $date]
- break
- }
-}
-close $in
+set PWD [pwd]
+cd $TOP
+set zSourceId [exec $PWD/mksourceid manifest]
+cd $PWD
# Set up patterns for recognizing API declarations.
#
@@ -125,7 +113,7 @@ foreach file $filelist {
regsub -- --VERS-- $line $zVersion line
regsub -- --VERSION-NUMBER-- $line $nVersion line
- regsub -- --SOURCE-ID-- $line "$zDate $zUuid" line
+ regsub -- --SOURCE-ID-- $line "$zSourceId" line
if {[regexp $varpattern $line] && ![regexp {^ *typedef} $line]} {
set line "SQLITE_API $line"
diff --git a/third_party/sqlite/src/tool/speed-check.sh b/third_party/sqlite/src/tool/speed-check.sh
index 22adec5..be79a1a 100644
--- a/third_party/sqlite/src/tool/speed-check.sh
+++ b/third_party/sqlite/src/tool/speed-check.sh
@@ -29,13 +29,14 @@ SIZE=5
LEAN_OPTS="-DSQLITE_THREADSAFE=0"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_DEFAULT_MEMSTATUS=0"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1"
-LEAN_OPTS="$LEAN_OPTS -DSQLITE_LIKE_DOESNT_MATCH_BLOB"
+LEAN_OPTS="$LEAN_OPTS -DSQLITE_LIKE_DOESNT_MATCH_BLOBS"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_MAX_EXPR_DEPTH=0"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_DECLTYPE"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_DEPRECATED"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_PROGRESS_CALLBACK"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_SHARED_CACHE"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_USE_ALLOCA"
+BASELINE="trunk"
doExplain=0
doCachegrind=1
while test "$1" != ""; do
@@ -116,9 +117,12 @@ while test "$1" != ""; do
--orm)
SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset orm"
;;
- *)
+ -*)
CC_OPTS="$CC_OPTS $1"
;;
+ *)
+ BASELINE=$1
+ ;;
esac
shift
done
@@ -147,10 +151,12 @@ size sqlite3.o | tee -a summary-$NAME.txt
wc sqlite3.c
if test $doCachegrind -eq 1; then
cg_anno.tcl cachegrind.out.* >cout-$NAME.txt
+ echo '*****************************************************' >>cout-$NAME.txt
+ sed 's/^[0-9=-]\{9\}/==00000==/' summary-$NAME.txt >>cout-$NAME.txt
fi
if test $doExplain -eq 1; then
./speedtest1 --explain $SPEEDTEST_OPTS | ./sqlite3 >explain-$NAME.txt
fi
-if test "$NAME" != "trunk"; then
- fossil test-diff --tk -c 20 cout-trunk.txt cout-$NAME.txt
+if test "$NAME" != "$BASELINE"; then
+ fossil test-diff --tk -c 20 cout-$BASELINE.txt cout-$NAME.txt
fi
diff --git a/third_party/sqlite/src/tool/split-sqlite3c.tcl b/third_party/sqlite/src/tool/split-sqlite3c.tcl
index 287b752..230e3f2 100644
--- a/third_party/sqlite/src/tool/split-sqlite3c.tcl
+++ b/third_party/sqlite/src/tool/split-sqlite3c.tcl
@@ -15,6 +15,7 @@ set END {^/\*+ End of %s \*+/}
set in [open sqlite3.c]
set out1 [open sqlite3-all.c w]
+fconfigure $out1 -translation lf
# Copy the header from sqlite3.c into sqlite3-all.c
#
@@ -48,6 +49,7 @@ proc write_one_file {content} {
global filecnt
incr filecnt
set out [open sqlite3-$filecnt.c w]
+ fconfigure $out -translation lf
puts -nonewline $out $content
close $out
puts $::out1 "#include \"sqlite3-$filecnt.c\""
diff --git a/third_party/sqlite/src/tool/sqlite3_analyzer.c.in b/third_party/sqlite/src/tool/sqlite3_analyzer.c.in
new file mode 100644
index 0000000..547b22f
--- /dev/null
+++ b/third_party/sqlite/src/tool/sqlite3_analyzer.c.in
@@ -0,0 +1,27 @@
+/*
+** Read an SQLite database file and analyze its space utilization. Generate
+** text on standard output.
+*/
+#define TCLSH_INIT_PROC sqlite3_analyzer_init_proc
+#define SQLITE_ENABLE_DBSTAT_VTAB 1
+#undef SQLITE_THREADSAFE
+#define SQLITE_THREADSAFE 0
+#undef SQLITE_ENABLE_COLUMN_METADATA
+#define SQLITE_OMIT_DECLTYPE 1
+#define SQLITE_OMIT_DEPRECATED 1
+#define SQLITE_OMIT_PROGRESS_CALLBACK 1
+#define SQLITE_OMIT_SHARED_CACHE 1
+#define SQLITE_DEFAULT_MEMSTATUS 0
+#define SQLITE_MAX_EXPR_DEPTH 0
+#define SQLITE_OMIT_LOAD_EXTENSION 1
+INCLUDE sqlite3.c
+INCLUDE $ROOT/src/tclsqlite.c
+
+const char *sqlite3_analyzer_init_proc(Tcl_Interp *interp){
+ (void)interp;
+ return
+BEGIN_STRING
+INCLUDE $ROOT/tool/spaceanal.tcl
+END_STRING
+;
+}
diff --git a/third_party/sqlite/src/tool/tostr.tcl b/third_party/sqlite/src/tool/tostr.tcl
deleted file mode 100644
index cb06ee9..0000000
--- a/third_party/sqlite/src/tool/tostr.tcl
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/tcl
-#
-# Convert input text into a C string
-#
-set in [open [lindex $argv 0] rb]
-while {![eof $in]} {
- set line [gets $in]
- if {[eof $in]} break;
- set x [string map "\\\\ \\\\\\\\ \\\" \\\\\"" $line]
- puts "\"$x\\n\""
-}
-close $in
diff --git a/third_party/sqlite/src/tool/warnings-clang.sh b/third_party/sqlite/src/tool/warnings-clang.sh
index 8d1e194..b7458d1 100644
--- a/third_party/sqlite/src/tool/warnings-clang.sh
+++ b/third_party/sqlite/src/tool/warnings-clang.sh
@@ -3,12 +3,12 @@
# Run this script in a directory with a working makefile to check for
# compiler warnings in SQLite.
#
-rm -f sqlite3.c
-make sqlite3.c
+rm -f sqlite3.c shell.c
+make sqlite3.c shell.c
echo '************* FTS4 and RTREE ****************'
scan-build gcc -c -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \
-DSQLITE_DEBUG -DSQLITE_ENABLE_STAT3 sqlite3.c 2>&1 | grep -v 'ANALYZE:'
echo '********** ENABLE_STAT3. THREADSAFE=0 *******'
scan-build gcc -c -I. -DSQLITE_ENABLE_STAT3 -DSQLITE_THREADSAFE=0 \
-DSQLITE_DEBUG \
- sqlite3.c ../sqlite/src/shell.c -ldl 2>&1 | grep -v 'ANALYZE:'
+ sqlite3.c shell.c -ldl 2>&1 | grep -v 'ANALYZE:'